When we try to access profile through code we are getting message as below, please advice
The error is:
There was an error in serializing one of the headers in message
EPS_ProfileReadRQRequest: 'Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'CRM.ProfileReadRQ.BusinessSystemIdentityInfoSynchronizationCriterionTypeExcludeCombination' to 'CRM.ProfileReadRQ.BusinessSystemIdentityInfoSynchronizationCriterionTypeIncludeCombination'
error CS0029: Cannot implicitly convert type 'CRM.ProfileReadRQ.BusinessSystemIdentityInfoSynchronizationCriterionTypeIncludeCombination' to 'CRM.ProfileReadRQ.BusinessSystemIdentityInfoSynchronizationCriterionTypeExcludeCombination'
This happens because the serializer doesn't know what type to cast to since the types that throw the error can be of more than one type. I think that simplifies the XML but it makes the WSDL/.NET stuff more complicated. I'm probably not saying that perfectly accurately but that's the gist of it, at least as I understand it.
You can go into your reference.cs file and remove the serialization for those offending fields and try again. I've done this in the past with some success. If/when you update the API version with a new WSDL file you'll have to remember to do it again, though, so it's not a perfect solution. I've got a sample of what I removed from my reference.cs file to get one of the profile APIs below, hopefully it's helpful.
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.7.3056.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.sabre.com/eps/schemas")]
public partial class BusinessSystemIdentityInfoSynchronizationCriterionType {
private BusinessSystemIdentityInfoSynchronizationCriterionTypeExcludeCombination[] itemsField;
private ItemsChoiceType1[] itemsElementNameField;
//remarked this out 12/24/18 - these include/exclude combinations do not serialize correctly for some reason
/// <remarks/>
//[System.Xml.Serialization.XmlElementAttribute("ExcludeCombination", typeof(BusinessSystemIdentityInfoSynchronizationCriterionTypeExcludeCombination))]
//[System.Xml.Serialization.XmlElementAttribute("IncludeCombination", typeof(BusinessSystemIdentityInfoSynchronizationCriterionTypeIncludeCombination))]
//[System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")]
//public BusinessSystemIdentityInfoSynchronizationCriterionTypeExcludeCombination[] Items {
// get {
// return this.itemsField;
// }
// set {
// this.itemsField = value;
// }
//}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("ItemsElementName")]
[System.Xml.Serialization.XmlIgnoreAttribute()]
public ItemsChoiceType1[] ItemsElementName {
get {
return this.itemsElementNameField;
}
set {
this.itemsElementNameField = value;
}
}
}
Related
I have some custom logging in my plugin and want to include the contents of my tracingService in my custom logging (which is called within a catch block, before the plugin finishes).
I cant seem to access the content of tracingService. I wonder if it is accessible at all?
I tried tracingService.ToString() just incase the devs had provided a useful overload, alas as expected I get name of the class "Microsoft.Crm.Sandbox.SandboxTracingService".
Obviously Dynamics CRM makes use of the tracingService content towards the end of the pipeline if it needs to.
Anybody have any ideas on this?
Kind Regards,
Gary
The tracing service does not provide access to the trace text during execution but that can be overcome by creating your own implementation of ITracingService. Note, you cannot get any text that was written to the trace log prior to the Execute method of your plugin being called - meaning if you have multiple plugins firing you won't get their trace output in the plugin that throws the exception.
public class CrmTracing : ITracingService
{
ITracingService _tracingService;
StringBuilder _internalTrace;
public CrmTracing(ITracingService tracingService)
{
_tracingService = tracingService;
_internalTrace = new StringBuilder();
}
public void Trace(string format, params object[] args)
{
if (_tracingService != null) _tracingService.Trace(format, args);
_internalTrace.AppendFormat(format, args).AppendLine();
}
public string GetTraceBuffer()
{
return _internalTrace.ToString();
}
}
Just instantiate it in your plugin passing in the CRM provided ITracingService. Since it is the same interface it works the same if you pass it to other classes and methods.
public class MyPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var tracingService = new CrmTracing((ITracingService)serviceProvider.GetService(typeof(ITracingService)));
tracingService.Trace("Works same as always.");
var trace = tracingService.GetTraceBuffer();
}
}
To get the traceInfo string from traceService at runtime I used debugger to interrogate the tracingService contents.
So the trace string is accessible from these expressions...
for Plugins
((Microsoft.Crm.Extensibility.PipelineTracingService)(tracingService)).TraceInfo
for CWA
((Microsoft.Crm.Workflow.WorkflowTracingService)(tracingService)).TraceInfo
You can drill into the tracing service by debugging and extract the expression.
However, at design time neither of these expressions seem to be accessible from any of the standard CRM 2011 SDK dlls... so not sure if its possible as yet.
So i'm having a weird issue with my service reference in my VS2010 project that i can't really figure out.
Any time i rebuild the soap service that the service reference is attached to i can no longer deserialize the data from one of the methods. All of the other methods work but one in particular just gets filled with null/default values instead of the correct values. I can confirm that the web service is still returning good data and looks to be in the correct format. Once i update the service reference it all works again until i rebuild.
When i go and look at the diff of the structure i see that the following files are now different:
Configuration.svcinfo
Configuration91.svcinfo
Reference.cs
Reference.svcmap
MyService.disco
MyService.wsdl
When i look in the wsdl it looks almost like the fields were re-ordered. But i don't see how that is possible.
Here is the header information for my web service
[WebService(Namespace = http://myservice/)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[Policy("ServerPolicy")]
Anyone know why this is happening with each rebuild?
EDIT: Here is an example.
For example here is a random change that was made, this class was not changed but only recompiled:
Before:
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
public string Userid {
get {
return this.useridField;
}
set {
this.useridField = value;
this.RaisePropertyChanged("Userid");
}
}
After:
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=2)]
public string Userid {
get {
return this.useridField;
}
set {
this.useridField = value;
this.RaisePropertyChanged("Userid");
}
}
I am use the FileHelper to parse CSV files. Error messages encountered when parsing the file are displayed to the end user. The end user may not be able to make sense of the technical error message. Not too many clerks know what an Int32 is or Class: UploadFooDto.
I would like to customize the error messages so they are more user friendly. Something like:
Line 1. Column 2. A string (a) was entered instead of a number
Line 2. Column 3. '13-14-15' is not a valid date
I cannot find anything in the API that would allow me to customize the error messages. The most I have so far are some extension methods to clean up the errors:
public static class FileHelperExceptionExtensions
{
public static string BuildMessage(this ErrorInfo error)
{
if (error.ExceptionInfo is ConvertException)
{
return ((ConvertException)error.ExceptionInfo).BuildMessage();
}
if (error.ExceptionInfo is BadUsageException)
{
var message = error.ExceptionInfo.Message;
var readTo = message.IndexOf("Class:");
return message.Substring(0, readTo);
}
return string.Format("Line: {0}. An unspecific error occured.", error.LineNumber);
}
public static string BuildMessage(this ConvertException exception)
{
return string.Format("Line: {0}. Column: {1}. Field: {2}. Cannot convert '{3}' to type: '{4}'", exception.LineNumber, exception.ColumnNumber, exception.FieldName, exception.FieldStringValue, exception.FieldType.Name);
}
}
but these extensions still leave a lot to be desired. Is it possible to customize the error messages?
It's hard to improve on your extension methods without it being more hassle than it's worth.
You cannot subclass the default converters (e.g., FileHelpers.ConvertHelpers.Int32Converter since they are internal and sealed). You could create your own custom converter for each type (and base it on the corresponding source code from FileHelpers, e.g., Int32Converter). Then you can raise an alternative to ConvertException (also sealed so you cannot subclass) which would format the message differently.
Here is the situation:
Silverlight 3 Application hits an asp.net hosted WCF service to get a list of items to display in a grid. Once the list is brought down to the client it is cached in IsolatedStorage. This is done by using the DataContractSerializer to serialize all of these objects to a stream which is then zipped and then encrypted. When the application is relaunched, it first loads from the cache (reversing the process above) and the deserializes the objects using the DataContractSerializer.ReadObject() method. All of this was working wonderfully under all scenarios until recently with the entire "load from cache" path (decrypt/unzip/deserialize) taking hundreds of milliseconds at most.
On some development machines but not all (all machines Windows 7) the deserialize process - that is the call to ReadObject(stream) takes several minutes an seems to lock up the entire machine BUT ONLY WHEN RUNNING IN THE DEBUGGER in VS2008. Running the Debug configuration code outside the debugger has no problem.
One thing that seems to look suspicious is that when you turn on stop on Exceptions, you can see that the ReadObject() throws many, many System.FormatException's indicating that a number was not in the correct format. When I turn off "Just My Code" thousands of these get dumped to the screen. None go unhandled. These occur both on the read back from the cache AND on a deserialization at the conclusion of a web service call to get the data from the WCF Service. HOWEVER, these same exceptions occur on my laptop development machine that does not experience the slowness at all. And FWIW, my laptop is really old and my desktop is a 4 core, 6GB RAM beast.
Again, no problems unless running under the debugger in VS2008. Anyone else seem this? Any thoughts?
Here is the bug report link: https://connect.microsoft.com/VisualStudio/feedback/details/539609/very-slow-performance-deserializing-using-datacontractserializer-in-a-silverlight-application-only-in-debugger
EDIT: I now know where the FormatExceptions are coming from. It seems that they are "by design" - they occur when when I have doubles being serialized that are double.NaN so that that xml looks like NaN...It seems that the DCS tries to parse the value as a number, that fails with an exception and then it looks for "NaN" et. al. and handles them. My problem is not that this does not work...it does...it is just that it completely cripples the debugger. Does anyone know how to configure the debugger/vs2008sp1 to handle this more efficiently.
cartden,
You may want to consider switching over to XMLSerializer instead. Here is what I have determined over time:
The XMLSerializer and DataContractSerializer classes provides a simple means of serializing and deserializing object graphs to and from XML.
The key differences are:
1.
XMLSerializer has much smaller payload than DCS if you use [XmlAttribute] instead of [XmlElement]
DCS always store values as elements
2.
DCS is "opt-in" rather than "opt-out"
With DCS you explicitly mark what you want to serialize with [DataMember]
With DCS you can serialize any field or property, even if they are marked protected or private
With DCS you can use [IgnoreDataMember] to have the serializer ignore certain properties
With XMLSerializer public properties are serialized, and need setters to be deserialized
With XmlSerializer you can use [XmlIgnore] to have the serializer ignore public properties
3.
BE AWARE! DCS.ReadObject DOES NOT call constructors during deserialization
If you need to perform initialization, DCS supports the following callback hooks:
[OnDeserializing], [OnDeserialized], [OnSerializing], [OnSerialized]
(also useful for handling versioning issues)
If you want the ability to switch between the two serializers, you can use both sets of attributes simultaneously, as in:
[DataContract]
[XmlRoot]
public class ProfilePerson : NotifyPropertyChanges
{
[XmlAttribute]
[DataMember]
public string FirstName { get { return m_FirstName; } set { SetProperty(ref m_FirstName, value); } }
private string m_FirstName;
[XmlElement]
[DataMember]
public PersonLocation Location { get { return m_Location; } set { SetProperty(ref m_Location, value); } }
private PersonLocation m_Location = new PersonLocation(); // Should change over time
[XmlIgnore]
[IgnoreDataMember]
public Profile ParentProfile { get { return m_ParentProfile; } set { SetProperty(ref m_ParentProfile, value); } }
private Profile m_ParentProfile = null;
public ProfilePerson()
{
}
}
Also, check out my Serializer class that can switch between the two:
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ClassLibrary
{
// Instantiate this class to serialize objects using either XmlSerializer or DataContractSerializer
internal class Serializer
{
private readonly bool m_bDCS;
internal Serializer(bool bDCS)
{
m_bDCS = bDCS;
}
internal TT Deserialize<TT>(string input)
{
MemoryStream stream = new MemoryStream(input.ToByteArray());
if (m_bDCS)
{
DataContractSerializer dc = new DataContractSerializer(typeof(TT));
return (TT)dc.ReadObject(stream);
}
else
{
XmlSerializer xs = new XmlSerializer(typeof(TT));
return (TT)xs.Deserialize(stream);
}
}
internal string Serialize<TT>(object obj)
{
MemoryStream stream = new MemoryStream();
if (m_bDCS)
{
DataContractSerializer dc = new DataContractSerializer(typeof(TT));
dc.WriteObject(stream, obj);
}
else
{
XmlSerializer xs = new XmlSerializer(typeof(TT));
xs.Serialize(stream, obj);
}
// be aware that the Unicode Byte-Order Mark will be at the front of the string
return stream.ToArray().ToUtfString();
}
internal string SerializeToString<TT>(object obj)
{
StringBuilder builder = new StringBuilder();
XmlWriter xmlWriter = XmlWriter.Create(builder);
if (m_bDCS)
{
DataContractSerializer dc = new DataContractSerializer(typeof(TT));
dc.WriteObject(xmlWriter, obj);
}
else
{
XmlSerializer xs = new XmlSerializer(typeof(TT));
xs.Serialize(xmlWriter, obj);
}
string xml = builder.ToString();
xml = RegexHelper.ReplacePattern(xml, RegexHelper.WildcardToPattern("<?xml*>", WildcardSearch.Anywhere), string.Empty);
xml = RegexHelper.ReplacePattern(xml, RegexHelper.WildcardToPattern(" xmlns:*\"*\"", WildcardSearch.Anywhere), string.Empty);
xml = xml.Replace(Environment.NewLine + " ", string.Empty);
xml = xml.Replace(Environment.NewLine, string.Empty);
return xml;
}
}
}
This is a guess, but I think it is running slow in debug mode because for every exception, it is performing some actions to show the exception in the debug window, etc. If you are running in release mode, these extra steps are not taken.
I've never done this, so I really don't know id it would work, but have you tried just setting that one assembly to run in release mode while all others are set to debug? If I'm right, it may solve your problem. If I'm wrong, then you only waste 1 or 2 minutes.
About your debugging problem, have you tried to disable the exception assistant ? (Tools > Options > Debugging > Enable the exception assistant).
Another point should be the exception handling in Debug > Exceptions : you can disable the user-unhandled stuff for the CLR or only uncheck the System.FormatException exception.
Ok - I figured out the root issue. It was what I alluded to in the EDIT to the main question. The problem was that in the xml, it was correctly serializing doubles that had a value of double.NaN. I was using these values to indicate "na" for when the denominator was 0D. Example: ROE (Return on Equity = Net Income / Average Equity) when Average Equity is 0D would be serialized as:
<ROE>NaN</ROE>
When the DCS tried to de-serialize it, evidently it first tries to read the number and then catches the exception when that fails and then handles the NaN. The problem is that this seems to generate a lot of overhead when in DEBUG mode.
Solution: I changed the property to double? and set it to null instead of NaN. Everything now happens instantly in DEBUG mode now. Thanks to all for your help.
Try disabling some IE addons. In my case, the LastPass toolbar killed my Silverlight debugging. My computer would freeze for minutes each time I interacted with Visual Studio after a breakpoint.
I am having a minor problem with WCF service proxies where the message contains List<string> as a parameter.
I am using the 'Add Service reference' in Visual Studio to generate a reference to my service.
// portion of my web service message
public List<SubscribeInfo> Subscribe { get; set; }
public List<string> Unsubscribe { get; set; }
These are the generated properties on my MsgIn for one of my web methods.
You can see it used ArrayOfString when I am using List<string>, and the other takes List<SubscribeInfo> - which matches my original C# object above.
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public System.Collections.Generic.List<DataAccess.MailingListWSReference.SubscribeInfo> Subscribe {
get {
return this.SubscribeField;
}
set {
if ((object.ReferenceEquals(this.SubscribeField, value) != true)) {
this.SubscribeField = value;
this.RaisePropertyChanged("Subscribe");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
publicDataAccess.MailingListWSReference.ArrayOfString Unsubscribe {
get {
return this.UnsubscribeField;
}
set {
if ((object.ReferenceEquals(this.UnsubscribeField, value) != true)) {
this.UnsubscribeField = value;
this.RaisePropertyChanged("Unsubscribe");
}
}
}
The ArrayOfString class generated looks like this. This is a class generated in my code - its not a .NET class. It actually generated me a class that inherits from List, but didn't have the 'decency' to create me any constructors.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.CollectionDataContractAttribute(Name="ArrayOfString", Namespace="http://www.example.com/", ItemName="string")]
[System.SerializableAttribute()]
public class ArrayOfString : System.Collections.Generic.List<string> {
}
The problem is that I often create my message like this :
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.ToList()
});
I really like the clean look this gives me.
Now for the actual problem :
I cant assign a List<string> to the Unsubscribe property which is an ArrayOfString - even though it inherits from List. In fact I cant seem to find ANY way to assign it without extra statements.
I've tried the following :
new ArrayOfString(unsubscribeFrom.ToList()) - this constructor doesn't exist :-(
changing the type of the array used by the code generator - doesn't work - it always gives me ArrayOfString (!?)
try to cast List<string> to ArrayOfString - fails with 'unable to cast', even though it compiles just fine
create new ArrayOfString() and then AddRange(unsubscribeFrom.ToList()) - works, but I cant do it all in one statement
create a conversion function ToArrayOfString(List<string>), which works but isn't as clean as I want.
Its only doing this for string, which is annoying.
Am i missing something? Is there a way to tell it not to generate ArrayOfString - or some other trick to assign it ?
Any .NET object that implements a method named "Add" can be initialized just like arrays or dictionaries.
As ArrayOfString does implement an "Add" method, you can initialize it like this:
var a = new ArrayOfString { "string one", "string two" };
But, if you really want to initialize it based on another collection, you can write a extension method for that:
public static class U
{
public static T To<T>(this IEnumerable<string> strings)
where T : IList<string>, new()
{
var newList = new T();
foreach (var s in strings)
newList.Add(s);
return newList;
}
}
Usage:
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.To<ArrayOfString>()
});
I prefer not to return generic types across a service boundary in the first place. Instead return Unsubscribe as a string[], and SubscriptionInfo as SubscriptionInfo[]. If necessary, an array can easily be converted to a generic list on the client, as follows:
Unsubscribe = new List<string>(unsubscribeFrom);
Subscribe = new List<SubscriptionInfo>(subscribeTo);
Too late but can help people in the future...
Use the svcutil and explicitly inform the command line util that you want the proxy class to be serialized by the XmlSerializer and not the DataContractSerializer (default). Here's the sample:
svcutil /out:c:\Path\Proxy.cs /config:c:\Path\Proxy.config /async /serializer:XmlSerializer /namespace:*,YourNamespace http://www.domain.com/service/serviceURL.asmx
Note that the web service is an ASP.NET web service ok?!
If you are using VS 2008 to consume service then there is an easy solution.
Click on the "Advanced..." button on the proxy dialog that is displayed when you add a Service Reference. In the Collection Type drop down you can select System.Generic.List. The methods returning List should now work properly.
(Hope this is what you were asking for, I'm a little tired and the question was a tad difficult for me to read.)