How can I make a deep copy of an object graph that has been loaded by Entity Framework Code First with proxies enabled?
I'm using code like this:
static public T DeepCopy<T>(T obj)
{
BinaryFormatter s = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
s.Serialize(ms, obj);
ms.Position = 0;
T t = (T)s.Deserialize(ms);
return t;
}
}
However, the serializer complains correctly that the proxy types are not known types.
UPDATE
Using DataContractSerializer with ProxyContractResolver does not work because my class is decorated with DataContract(IsReference = true).
See
Serialize EF Proxy when POCO has IsReference = true Attribute
Related
Need to create a digital signed excel file and then validate the signature when uploaded in C#.
On its own, the SpreadsheetDocument.AddDigitalSignatureOriginPart() method does not secure an Excel file. The same is true for the corresponding methods of the WordprocessingDocument and PresentationDocument classes. Those methods only add an empty DigitalSignatureOriginPart that serves as the origin of one or more XmlSignaturePart instances, each of which contains a ds:Signature element based on the W3C Recommendation XML Signature Syntax and Processing Version 1.1 (XMLDSIG).
To secure an Excel file, or any file based on the Open Packaging Conventions (OPC), the most straightforward approach is to use the PackageDigitalSignatureManager class, which is contained in the System.IO.Packaging namespace as provided by the WindowsBase.dll assembly. Thus, if you are targeting the full .NET Framework (e.g., net471), you can use it. However, if you are targeting .Net Core, you need to implement that functionality yourself.
The following code example shows how you can use the PackageDigitalSignatureManager class:
using System;
using System.Collections.Generic;
using System.IO.Packaging;
using System.Linq;
namespace CodeSnippets.Windows.IO.Packaging
{
public static class DigitalSignatureManager
{
public static void Sign(Package package)
{
var dsm = new PackageDigitalSignatureManager(package)
{
CertificateOption = CertificateEmbeddingOption.InSignaturePart
};
List<Uri> parts = package.GetParts()
.Select(part => part.Uri)
.Concat(new[]
{
// Include the DigitalSignatureOriginPart and corresponding
// relationship part, since those will only be added when
// signing.
dsm.SignatureOrigin,
PackUriHelper.GetRelationshipPartUri(dsm.SignatureOrigin)
})
.ToList();
dsm.Sign(parts);
}
public static VerifyResult VerifySignature(Package package)
{
var dsm = new PackageDigitalSignatureManager(package);
return dsm.VerifySignatures(true);
}
}
}
In case you need to implement that functionality yourself, it helps to make yourself familiar with a number of sources:
The Digital Signing Framework of the Open Packaging Conventions
How to: Sign XML Documents with Digital Signatures
System.Security.Cryptography.Xml Namespace
Based on those sources, I created a partial sample implementation that works with .Net Core. The following snippet shows the void Sign(OpenXmlPackage, X509Certificate2) method that takes an OpenXmlPackage and an X509Certificate2 and creates a valid signature:
public static void Sign(OpenXmlPackage openXmlPackage, X509Certificate2 certificate)
{
if (openXmlPackage == null) throw new ArgumentNullException(nameof(openXmlPackage));
if (certificate == null) throw new ArgumentNullException(nameof(certificate));
RSA privateKey = certificate.GetRSAPrivateKey();
using SHA256 hashAlgorithm = SHA256.Create();
// Create KeyInfo.
var keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(certificate));
// Create a Signature XmlElement.
var signedXml = new SignedXml { SigningKey = privateKey, KeyInfo = keyInfo };
signedXml.Signature.Id = Constants.PackageSignatureId;
signedXml.SignedInfo.SignatureMethod = Constants.SignatureMethod;
signedXml.AddReference(CreatePackageObjectReference());
signedXml.AddObject(CreatePackageObject(openXmlPackage.Package, hashAlgorithm));
signedXml.ComputeSignature();
XmlElement signature = signedXml.GetXml();
// Get or create the DigitalSignatureOriginPart.
DigitalSignatureOriginPart dsOriginPart =
openXmlPackage.GetPartsOfType<DigitalSignatureOriginPart>().FirstOrDefault() ??
openXmlPackage.AddNewPart<DigitalSignatureOriginPart>();
var xmlSignaturePart = dsOriginPart.AddNewPart<XmlSignaturePart>();
// Write the Signature XmlElement to the XmlSignaturePart.
using Stream stream = xmlSignaturePart.GetStream(FileMode.Create, FileAccess.Write);
using XmlWriter writer = XmlWriter.Create(stream);
signature.WriteTo(writer);
}
The full source code of the above void Sign(OpenXmlPackage, X509Certificate2) method can be found in my CodeSnippets GitHub repository. Look for the DigitalSignatureManager class in the CodeSnippets project.
Background
I am developing a Web application based on ASP.NET Core 2.1 and EntityFrameworkCore 2.1.1. Besides other type of tests, I am using InMemory Web API testing to have some kind of integration testing of the Web.Api.
Since test data is rather convoluted I have generated a JSON file based on a slice of a migrated database and testing is importing data from this JSON file when the in-memory tests kick in.
The issue
Read-only tests are working just fine. However, when I insert something for an entity that has an identity (ValueGenerated == ValueGenerated.OnAdd) it automatically gets a value of 1 (all PKs are ints). This makes sense since whatever generator EF is using behind the scene to generate those values was not instructed to generate from a certain value.
However, this is clearly not working properly for inserts that generate an existing key value.
Things I have tried
[current working solution] Shifting the key values - Upon deserializing all objects, I perform an ids shift operations for all involved entities (they get "large" values). This works properly, but it is error prone (e.g. some entities have static ids, I have to ensure that all foreign keys / navigations properties are properly defined and it is kind of slow right now since I rely on reflection to properly identity the keys / navigation properties that require shifting)
Configuring value generator to start from a large value:
TestStartUp.cs
services.AddSingleton<IValueGeneratorCache, ValueGeneratorCache>();
services.AddSingleton<ValueGeneratorCacheDependencies, ValueGeneratorCacheDependencies>();
Ids generation functionality
public const int StartValue = 100000000;
class ResettableValueGenerator : ValueGenerator<int>
{
private int _current;
public override bool GeneratesTemporaryValues => false;
public override int Next(EntityEntry entry)
{
return Interlocked.Increment(ref _current);
}
public void Reset() => _current = StartValue;
}
public static void ResetValueGenerators(CustomApiContext context, IValueGeneratorCache cache, int startValue = StartValue)
{
var allKeyProps = context.Model.GetEntityTypes()
.Select(e => e.FindPrimaryKey().Properties[0])
.Where(p => p.ClrType == typeof(int));
var keyProps = allKeyProps.Where(p => p.ValueGenerated == ValueGenerated.OnAdd);
foreach (var keyProperty in keyProps)
{
var generator = (ResettableValueGenerator)cache.GetOrAdd(
keyProperty,
keyProperty.DeclaringEntityType,
(p, e) => new ResettableValueGenerator());
generator.Reset();
}
}
When debugging I can see that my entities being iterated, so the reset is applied.
Pushing the data into the in-memory database
private void InitializeSeeding(IServiceScope scope)
{
using (scope)
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<CustomApiContext>();
// this pushes deserialized data + static data into the database
InitDbContext(context);
var valueGeneratorService = services.GetRequiredService<IValueGeneratorCache>();
ResetValueGenerators(context, valueGeneratorService);
}
catch (Exception ex)
{
var logger = services.GetService<ILogger<Startup>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
}
}
Actual insert
This is done using a generic repository, but boils down to this:
Context.Set<T>().Add(entity);
Context.SaveChanges();
Question: How to control in-memory generated key values in Entity Framework Core?
I've an error: "ExceptionMessage": "Self referencing loop detected for property 'Posto' with type 'UfficioServer.Posto'. Path '[0].Dipendente[0]'.",
when i call my web api, i need a list of Posti whit the association with Dipendente...
public List<Posto> GetAllPosti()
{
try
{
List<Posto> p = new List<Posto>();
UfficioPostiEntities1 db = new UfficioPostiEntities1();
db.Configuration.ProxyCreationEnabled = false;
var posto = db.Posto.Include("Dipendente").ToList();
var x = db.Posto.ToList();
return x;
}
can someone help me?
To avoid this error you should add the following to the Application_Start in Global.asax:
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter
.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
This is because (as per documentation)
ReferenceLoopHandling.Ignore: Json.NET will ignore objects in
reference loops and not serialize them. The first time an object is
encountered it will be serialized as usual but if the object is
encountered as a child object of itself the serializer will skip
serializing it.
I had experience in developing reports(SSRS) using ado.net dataset. Now I am working on an application which is not using ADO.net but entity framework but entity framework does not return datatable or dataset. I want to know
Is there any way to use Collection or custom objects return by entity framework in the reporting services?
Entity framework somehow return datatable or dataset.
Or I should create datatable/dataset from the collection returned by entity framework manually.
For the record, I am getting resultset by executing stored procedure from entity framework.
public void getMyReportData()
{
using (myEntityDataModel v = new myEntityDataModel())
{
var reportQuery = (from r in v.myTable
select new
{
l.ID,
l.LeaveApplicationDate,
l.EmployeeNumber,
l.EmployeeName,
l.StartDate,
l.Col1,
l.Col2,
.......,
.......,
l.Address
}).ToList();
reportViewer1.LocalReport.DataSources.Clear();
ReportDataSource datasource = new ReportDataSource("nameOfReportDataset", reportQuery);
reportViewer1.LocalReport.DataSources.Add(datasource);
Stream rpt = loadEmbededReportDefinition("Report1.rdlc");
reportViewer1.LocalReport.LoadReportDefinition(rpt);
reportViewer1.RefreshReport();
//Another way of setting the reportViewer report source
string exeFolder = Path.GetDirectoryName(Application.ExecutablePath);
string reportPath = Path.Combine(exeFolder, #"rdlcReports\Report1.rdlc");
reportViewer1.LocalReport.ReportPath = reportPath;
reportParameter p = new ReportParameter("DeptID", deptID.ToString());
reportViewer1.LocalReport.SetParameters(new[] { p });
}
}
public static Stream loadEmbededReportDefinition(string reportName)
{
Assembly _assembly = Assembly.GetExecutingAssembly();
Stream _reportStream = _assembly.GetManifestResourceStream("ProjectNamespace.rdlcReportsFolder." + reportName);
return _reportStream;
}
Original source: Creating Reports in ASP.Net with Entity Framework
I am getting started with Entity Framework 4, and I an creating a demo app as a learning exercise. The app is a simple documentation builder, and it uses a SQL CE store. Each documentation project has its own SQL CE data file, and the user opens one of these files to work on a project.
The EDM is very simple. A documentation project is comprised of a list of subjects, each of which has a title, a description, and zero or more notes. So, my entities are Subject, which contains Title and Text properties, and Note, which has Title and Text properties. There is a one-to-many association from Subject to Note.
I am trying to figure out how to open an SQL CE data file. A data file must match the schema of the SQL CE database created by EF4's Create Database Wizard, and I will implement a New File use case elsewhere in the app to implement that requirement. Right now, I am just trying to get an existing data file open in the app.
I have reproduced my existing 'Open File' code below. I have set it up as a static service class called File Services. The code isn't working quite yet, but there is enough to show what I am trying to do. I am trying to hold the ObjectContext open for entity object updates, disposing it when the file is closed.
So, here is my question: Am I on the right track? What do I need to change to make this code work with EF4? Is there an example of how to do this properly?
Thanks for your help.
My existing code:
public static class FileServices
{
#region Private Fields
// Member variables
private static EntityConnection m_EntityConnection;
private static ObjectContext m_ObjectContext;
#endregion
#region Service Methods
/// <summary>
/// Opens an SQL CE database file.
/// </summary>
/// <param name="filePath">The path to the SQL CE file to open.</param>
/// <param name="viewModel">The main window view model.</param>
public static void OpenSqlCeFile(string filePath, MainWindowViewModel viewModel)
{
// Configure an SQL CE connection string
var sqlCeConnectionString = string.Format("Data Source={0}", filePath);
// Configure an EDM connection string
var builder = new EntityConnectionStringBuilder();
builder.Metadata = "res://*/EF4Model.csdl|res://*/EF4Model.ssdl|res://*/EF4Model.msl";
builder.Provider = "System.Data.SqlServerCe";
builder.ProviderConnectionString = sqlCeConnectionString;
var entityConnectionString = builder.ToString();
// Connect to the model
m_EntityConnection = new EntityConnection(entityConnectionString);
m_EntityConnection.Open();
// Create an object context
m_ObjectContext = new Model1Container();
// Get all Subject data
IQueryable<Subject> subjects = from s in Subjects orderby s.Title select s;
// Set view model data property
viewModel.Subjects = new ObservableCollection<Subject>(subjects);
}
/// <summary>
/// Closes an SQL CE database file.
/// </summary>
public static void CloseSqlCeFile()
{
m_EntityConnection.Close();
m_ObjectContext.Dispose();
}
#endregion
}
Here is the answer. I simplified my code and ran it on simpler EDM model, Disney Characters. Model has two entities, Character and Child, with a 1:* association between Character and Child. Children are character's kids--pretty simple stuff. I wrote the demo as a console app to keep it as simple as possible.
Complete code in Program.cs is as follows:
class Program
{
static void Main(string[] args)
{
/* See http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/8a89a728-6c8d-4734-98cb-11b196ba11fd */
// Configure an SQL CE connection string
var filePath = #"D:\Users\dcveeneman\Documents\Visual Studio 2010\Demos\SqlCeEf4Demo\SqlCeEf4Demo\DisneyChars.sdf";
var sqlCeConnectionString = string.Format("Data Source={0}", filePath);
// Create an EDM connection
var builder = new EntityConnectionStringBuilder();
builder.Metadata = "res://*/DisneyChars.csdl|res://*/DisneyChars.ssdl|res://*/DisneyChars.msl";
builder.Provider = "System.Data.SqlServerCe.3.5";
builder.ProviderConnectionString = sqlCeConnectionString;
var edmConnectionString = builder.ToString();
var edmConnection = new EntityConnection(edmConnectionString);
// Build and query an ObjectContext
using (var context = new DisneyCharsContainer(edmConnection))
{
var chars = context.Characters;
foreach(var character in chars)
{
Console.WriteLine("Character name: {0}", character.Name);
foreach(var child in character.Children)
{
Console.WriteLine("Child name: {0}", child.Name);
}
}
Console.ReadLine();
}
}
}
Link at the top of the code is to a forum thread that I used to write the code.
Here is the walkthrough: First, create a database connection. Since I am using SQL CE, I don't have a connection string builder--the connection string is simply a path, so I don't need one. Then I use an EntityConnectionStringBuilder to build an entity connection string, and then I use that to build an EntityConnection. Finally, I pass the connection to the constructor for my ObjectContext. I can then use the ObjectContext to query the EDM.
Finding / opening a SQL Server CE database is, for some weird reason, hard to do. Make sure you can make any kind of connection to the DB at all before trying to get it to work with the EF.