Gurus,
I want to serialize the Entityframe Work object (underlying object is from Oracle table). I'm using the LINQ Query.
Code Snippet
using (Entities1 ctx = new Entities1())
{
ctx.Configuration.ProxyCreationEnabled = false;
var oraLINQ1 = from ime in ctx.INV_MOVE_EVENT
select new
{
ime.TO_POS_SLOT
};
var bformatter = new BinaryFormatter();
Stream stream = File.Open("INVMOVEEVENT.ifl", FileMode.Create);
bformatter.Serialize(stream, oraLINQ1);
stream.Close();
}
I get an exception
"Type 'System.Data.Entity.Infrastructure.DbQuery`1[[<>f__AnonymousType0`1[[System.String,
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], EntityFramework,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' in Assembly 'EntityFramework,
Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as
serializable."} System.Exception {System.Runtime.Serialization.SerializationException}
I tried INV_MOVE_EVENT entity class inheriting ISerializable. It didn't work. Any clues pointing to the right direction is highly appreciated.
I can't test it here in my side, but have you tried to convert the query to a list?
using (Entities1 ctx = new Entities1())
{
ctx.Configuration.ProxyCreationEnabled = false;
var oraLINQ1 = from ime in ctx.INV_MOVE_EVENT
select new
{
ime.TO_POS_SLOT
};
var bformatter = new BinaryFormatter();
Stream stream = File.Open("INVMOVEEVENT.ifl", FileMode.Create);
bformatter.Serialize(stream, oraLINQ1.ToList());
stream.Close();
}
It should work fine.
Related
I am writing a plugin that deletes records between two dates when a contract is cancelled... The records to be deleted are from the cancellation date to the end of the contract. Here is the code I am using:
using System;
using System.Linq;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
/// <summary>
/// This plugin will trimm off unit orders after a contract is cancelled before the end of the contract duration
/// </summary>
namespace DCWIMS.Plugins
{
[CrmPluginRegistration(MessageNameEnum.Update,
"contract",
StageEnum.PostOperation,
ExecutionModeEnum.Asynchronous,
"statecode",
"Post-Update On Cancel Contract",
1000,
IsolationModeEnum.Sandbox,
Image1Name = "PreImage",
Image1Type = ImageTypeEnum.PreImage,
Image1Attributes = "")]
public class UnitPluginOnCancel : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Extract the tracing service for use in debugging sandboxed plug-ins.
// Will be registering this plugin, thus will need to add tracing service related code.
ITracingService tracing = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
//obtain execution context from service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
// InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
//Get the before image of the updated contract
Entity PreImage = context.PreEntityImages["PreImage"];
//verify that the target entity represents the the contract entity has been cancelled
if (entity.LogicalName != "contract" || entity.GetAttributeValue<OptionSetValue>("statecode").Value != 4)
return;
//obtain the organization service for web service calls.
IOrganizationServiceFactory serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//Core Plugin code in Try Block
try
{
//Get Contract line start date
var startDate = entity.GetAttributeValue<DateTime>("cancelon");
//Get Contract Line End Date
DateTime endDate = (DateTime)PreImage["expireson"];
//Get Contract range into weekdays list
Eachday range = new Eachday();
var weekdays = range.WeekDay(startDate, endDate);
//Get Unit Order Lookup Id
EntityReference unitOrder = (EntityReference)PreImage.Attributes["new_unitorderid"];
var unitOrderId = unitOrder.Id;
var unitOrders = service.Retrieve(unitOrder.LogicalName, unitOrder.Id, new ColumnSet("new_name"));
var uiName = unitOrders.GetAttributeValue<string>("new_name");
//Get Entity Collection to delete
string fetchXml = #" <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' top='2000'>
<entity name='new_units'>
<link-entity name='new_alterunitorder' from ='new_orderlineid' to = 'new_unitsid' >
<attribute name='new_alterunitorderid' />
<filter type='and'>
<condition attribute='new_orderdate' operator='on-or-after' value='" + startDate.ToShortDateString() + #"' />
<condition attribute='new_orderdate' operator='on-or-before' value='" + endDate.ToShortDateString() + #"' />
<condition attribute='new_orderlineid' operator='eq' uiname='" + uiName + #"' uitype='new_units' value='" + unitOrderId + #"' />
</filter>
</link-entity>
</entity>
</fetch>";
var result = service.RetrieveMultiple(new FetchExpression(fetchXml));
var entityRefs = result.Entities.Select(e => e.GetAttributeValue<EntityReference>("new_alterunitorderid"));
var batchSize = 1000;
var batchNum = 0;
var numDeleted = 0;
while (numDeleted < entityRefs.Count())
{
var multiReq = new ExecuteMultipleRequest()
{
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = false
},
Requests = new OrganizationRequestCollection()
};
var currentList = entityRefs.Skip(batchSize * batchNum).Take(batchSize).ToList();
currentList.ForEach(r => multiReq.Requests.Add(new DeleteRequest { Target = r }));
service.Execute(multiReq);
numDeleted += currentList.Count;
batchNum++;
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occured.. Phil is responsible. ", ex);
}
catch (Exception ex)
{
tracing.Trace("An error occured: {0}", ex.ToString());
throw;
}
}
}
}
}
I am getting a NullReferenceException on line 55... I have literally used the same line for a previous plugin without any problems.. The statecode for a cancelled contract has a value of 4 and I only want the plugin to execute when the contract has been cancelled. Here is an image of the debugging.
I have used this statement before for another plugin that acts on the contract entity and it worked fine, I don't know why this time it's not working. Here is the statement:
//verify that the target entity represents the the contract entity has been cancelled
if (entity.LogicalName != "contract" || entity.GetAttributeValue<OptionSetValue>("statecode").Value != 4)
return;
The entity you get from the input parameters may not have StateCode in it, so .Value is failing.
Maybe try entity.GetAttributeValue<OptionSetValue>("statecode") or entity.Contains("statecode") to see if there's anything there before you dereference .Value.
Since you have the PreImage, you may want to look there for the statecode.
Check to see if you are using the right profile while debugging... If you are using the wrong profile, a null reference will through on a method when it shouldn't!
Hope that helps!
I'm just wondering if someone could explain what is happening here.
Given this Post method on an API controller:
public HttpResponseMessage PostImage()
{
var request = HttpContext.Current.Request;
var c = SynchronizationContext.Current;
var result = new HttpResponseMessage(HttpStatusCode.OK);
if (Request.Content.IsMimeMultipartContent())
{
Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider()).ContinueWith((task) =>
{
MultipartMemoryStreamProvider provider = task.Result;
foreach (HttpContent content in provider.Contents)
{
Stream stream = content.ReadAsStreamAsync().Result;
Image image = Image.FromStream(stream);
var uploadFileName = content.Headers.ContentDisposition.FileName;
var requestInside = HttpContext.Current.Request; // this is always null
string filePath = Path.Combine(HostingEnvironment.MapPath(ConfigurationManager.AppSettings["UserFilesRootDir"]), userprofile.UserCode);
//string[] headerValues = (string[])Request.Headers.GetValues("UniqueId");
string fileName = userprofile.UserCode + ".jpg";
string fullPath = Path.Combine(filePath, fileName);
image.Save(fullPath);
}
});
return result;
}
}
Why would var requestInside = HttpContext.Current.Request; be null?
I've checked all the relevant settings:
<compilation debug="true" targetFramework="4.5">
...
<httpRuntime targetFramework="4.5"
And SynchronizationContext.Current is the newer AspNetSynchronizationContext rather than LegacyAspNetSynchronizationContext.
I'm presuming at the moment that it's because I'm on a different thread, is this a correct assumption?
ContinueWith is not guaranteed to run on the same thread hence the synchronization context could be lost. You could change your call to specify to resume on the current thread with parameter TaskScheduler.Current. See this previous SO answer.
If you use await/async pattern it will automatically capture the current syncronization context on resume once an awaitable operation completes. This is done by resuming the operation on the same thread which is bound to that context. An added benefit, IMHO, is cleaner looking code.
You can change your code to this which uses that pattern. I have not made any other changes to it other than use async/await.
public async Task<HttpResponseMessage> PostImage()
{
var request = HttpContext.Current.Request;
var c = SynchronizationContext.Current;
var result = new HttpResponseMessage(HttpStatusCode.OK);
if (Request.Content.IsMimeMultipartContent())
{
MultipartMemoryStreamProvider provider = await Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider());
foreach (HttpContent content in provider.Contents)
{
Stream stream = await content.ReadAsStreamAsync();
Image image = Image.FromStream(stream);
var uploadFileName = content.Headers.ContentDisposition.FileName;
var requestInside = HttpContext.Current.Request; // this is always null
string filePath = Path.Combine(HostingEnvironment.MapPath(ConfigurationManager.AppSettings["UserFilesRootDir"]), userprofile.UserCode);
//string[] headerValues = (string[])Request.Headers.GetValues("UniqueId");
string fileName = userprofile.UserCode + ".jpg";
string fullPath = Path.Combine(filePath, fileName);
image.Save(fullPath);
}
}
return result;
}
I am trying to serialize a list of (ValidationAttribute) as shown below:
RequiredAttribute tRequired = new RequiredAttribute();
List<ValidationAttribute> ValidationList = new List<ValidationAttribute>();
ValidationList.Add(tRequired);
XmlSerializer tXMLSerializer = new XmlSerializer(typeof(List<ValidationAttribute>));
MemoryStream tMemStream = new MemoryStream();
StreamWriter tStreamWriter = new StreamWriter(tMemStream);
tXMLSerializer.Serialize(tStreamWriter, ValidationList);
When the (Serialize) function execute, the following exception will be thrown:
The type System.ComponentModel.DataAnnotations.RequiredAttribute was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically
I have figured it out. I needed to pass the type of (RequiredAttribute) to the XMLSerializer:
RequiredAttribute tRequired = new RequiredAttribute();
List<ValidationAttribute> ValidationList = new List<ValidationAttribute>();
ValidationList.Add(tRequired);
Type[] tExtraTypes = new Type[] { typeof(RequiredAttribute) };
XmlSerializer tXMLSerializer = new XmlSerializer(typeof(List<ValidationAttribute>),tExtraTypes );
I followed this example Changing schema name on runtime - Entity Framework where I can create a new EntityConnection from a MetaDataWorkspace that I then use to construct a DbContext with a different schema, but I get compiler warnings saying that RegisterItemCollection method is obsolete and to "Construct MetadataWorkspace using constructor that accepts metadata loading delegates."
How do I do that? Here is the code that is working but gives the 3 warnings for the RegsiterItemCollection calls. I'm surprised it works since warning says obsolete not just deprecated.
public static EntityConnection CreateEntityConnection(string schema, string connString, string model)
{
XmlReader[] conceptualReader = new XmlReader[]
{
XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".csdl")
)
};
XmlReader[] mappingReader = new XmlReader[]
{
XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".msl")
)
};
var storageReader = XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".ssdl")
);
//XNamespace storageNS = "http://schemas.microsoft.com/ado/2009/02/edm/ssdl"; // this would not work!!!
XNamespace storageNS = "http://schemas.microsoft.com/ado/2009/11/edm/ssdl";
var storageXml = XElement.Load(storageReader);
foreach (var entitySet in storageXml.Descendants(storageNS + "EntitySet"))
{
var schemaAttribute = entitySet.Attributes("Schema").FirstOrDefault();
if (schemaAttribute != null)
{
schemaAttribute.SetValue(schema);
}
}
storageXml.CreateReader();
StoreItemCollection storageCollection =
new StoreItemCollection(
new XmlReader[] { storageXml.CreateReader() }
);
EdmItemCollection conceptualCollection = new EdmItemCollection(conceptualReader);
StorageMappingItemCollection mappingCollection =
new StorageMappingItemCollection(
conceptualCollection, storageCollection, mappingReader
);
//var workspace2 = new MetadataWorkspace(conceptualCollection, storageCollection, mappingCollection);
var workspace = new MetadataWorkspace();
workspace.RegisterItemCollection(conceptualCollection);
workspace.RegisterItemCollection(storageCollection);
workspace.RegisterItemCollection(mappingCollection);
var connectionData = new EntityConnectionStringBuilder(connString);
var connection = DbProviderFactories
.GetFactory(connectionData.Provider)
.CreateConnection();
connection.ConnectionString = connectionData.ProviderConnectionString;
return new EntityConnection(workspace, connection);
}
I was able to get rid of the 3 warning messages. Basically it wants you to register the collections in the constructor of the MetadataWorkspace.
There are 3 different overloads for MetadataWorkspace, I chose to use the one which requires to to supply a path (array of strings) to the workspace metadata. To do this I saved readers to temp files and reloaded them.
This is working for me without any warnings.
public static EntityConnection CreateEntityConnection(string schema, string connString, string model) {
var conceptualReader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream(model + ".csdl"));
var mappingReader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream(model + ".msl"));
var storageReader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream(model + ".ssdl"));
XNamespace storageNS = "http://schemas.microsoft.com/ado/2009/11/edm/ssdl";
var storageXml = XElement.Load(storageReader);
var conceptualXml = XElement.Load(conceptualReader);
var mappingXml = XElement.Load(mappingReader);
foreach (var entitySet in storageXml.Descendants(storageNS + "EntitySet")) {
var schemaAttribute = entitySet.Attributes("Schema").FirstOrDefault();
if (schemaAttribute != null) {
schemaAttribute.SetValue(schema);
}
}
storageXml.Save("temp.ssdl");
conceptualXml.Save("temp.csdl");
mappingXml.Save("temp.msl");
MetadataWorkspace workspace = new MetadataWorkspace(new List<String>(){
#"temp.csdl",
#"temp.ssdl",
#"temp.msl"
}
, new List<Assembly>());
var connectionData = new EntityConnectionStringBuilder(connString);
var connection = DbProviderFactories.GetFactory(connectionData.Provider).CreateConnection();
connection.ConnectionString = connectionData.ProviderConnectionString;
return new EntityConnection(workspace, connection);
}
Not wanting to create temp files which slows the process down, I found an alternate answer to this is fairly simple. I replaced these lines of code -
//var workspace2 = new MetadataWorkspace(conceptualCollection, storageCollection, mappingCollection);
var workspace = new MetadataWorkspace();
workspace.RegisterItemCollection(conceptualCollection);
workspace.RegisterItemCollection(storageCollection);
workspace.RegisterItemCollection(mappingCollection);
with this one line of code -
var workspace = new MetadataWorkspace(() => conceptualCollection, () => storageCollection, () => mappingCollection);
and that works fine.
I am making a request to a service and getting a response. Service works fine and I am deserializing an object without a problem.
Below is an example of my code. The problem is the result object is null at the end. I do not know why am I losing a reference. What is the proper solution?
HttpWebRequest hwrq = (HttpWebRequest)WebRequest.Create("http://service.svc/Login");
hwrq.ContentType = "application/x-www-form-urlencoded; encoding='utf-8'";
hwrq.Accept = "text/xml";
hwrq.Method = "POST";
Users result = null; // object initializaiton
hwrq.BeginGetRequestStream(ar =>
{
var requestStream = hwrq.EndGetRequestStream(ar);
using (var sw = new StreamWriter(requestStream, System.Text.Encoding.UTF8))
{
sw.Write("Username Password");
sw.Close();
}
hwrq.BeginGetResponse(a =>
{
var response = hwrq.EndGetResponse(a);
var responseStream = response.GetResponseStream();
using (var sr = new StreamReader(responseStream))
{
returnedXML = sr.ReadToEnd();
XmlSerializer xds = new XmlSerializer(typeof(Users));
byte[] byteArray = Encoding.UTF8.GetBytes(returnedXML);
MemoryStream stream = new MemoryStream(byteArray);
result = (Users)xds.Deserialize(stream); // object is correct
}
responseStream.Close();
response.Close();
}, null);
}, null);
return result; // object is null!
Just like MarcinJuraszek suggested, the proper way is to make a callback and handle the results there.