How can I serialize a Collection to send it using WCF? - c#

I am trying to send a object via WCF as parameter in this method:
[OperationContract]
bool SendProject(Project project);
and I got this if i try to call it from client:
There was an error while trying to serialize parameter project. The InnerException message was 'Type 'System.Collections.ObjectModel.Collection`1[[System.Collections.DictionaryEntry, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'
with data contract name 'ArrayOfDictionaryEntry:http://schemas.datacontract.org/2004/07/System.Collections' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example,
by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'.
Please see InnerException for more details.
I search some info and I think that the error is how I serialize a class (a class from Dr. WPF) which is inside "project" class:
#region ISerializable
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
{
throw new ArgumentNullException("info");
}
Collection<DictionaryEntry> entries = new Collection<DictionaryEntry>();
foreach (DictionaryEntry entry in _keyedEntryCollection)
entries.Add(entry);
info.AddValue("entries", entries);
}
#endregion ISerializable
The problem is that I dont know where to put the tag "KnownType" or how to serialize correctly this Dictionary to send it as parameter using WCF.
Thanks!

I have the solution, which is not so clean but is a solution.
As dbc said, updating DictionaryEntry to KeyValuePair<TKey,TValue> is a recommended step, but what fixed my problem was set [KnownType(typeof(Collection<KeyValuePair<TypeX, TypeY>>))] in the class where the serialization is.

Related

CRM 2015 SDK : The deserializer has no knowledge of any type that maps to this name

I am currently working with CRM 2015 SDK. I am simply trying to update a value in C# with this SDK. But for some reasons that I try to figure out, there is a trouble when I save my context.
There is the code :
foreach (KeyValuePair<string, Account> account in dicAccount)
{
//Calcul of url/login/date/key/customer values
string generatedUrl = Utilities.GenerateURL(url, login, date, key, customer);
account.Value.new_Link = generatedUrl;
if (!context.IsAttached(account.Value))
{
context.Attach(account.Value);
}
context.UpdateObject(account.Value);
}
SaveChangesResultCollection results = context.SaveChanges(SaveChangesOptions.ContinueOnError);
if (results != null)
{
foreach (SaveChangesResult result in results)
{
Type type = result.Request.GetType();
bool hasError = result.Error != null;
Entity entity = (Entity)result.Request.Parameters["Target"];
if (type == typeof(UpdateRequest))
{
if (hasError)
{
if (entity != null)
{
log.Error(result.Error.Message);
}
}
}
On my Dynamics entities, I have this :
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("new_link")]
public string new_Link
{
get
{
return this.GetAttributeValue<string>("new_link");
}
set
{
this.OnPropertyChanging("new_link");
this.SetAttributeValue("new_link", value);
this.OnPropertyChanged("new_link");
}
}
Right now, I got this error printed by the LogError :
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://schemas.microsoft.com/xrm/2011/Contracts/Services:request. The InnerException message was 'Error in line 1 position 12271. Element 'http://schemas.datacontract.org/2004/07/System.Collections.Generic:value' contains data from a type that maps to the name 'http://schemas.microsoft.com/xrm/7.1/Contracts:ConcurrencyBehavior'. The deserializer has no knowledge of any type that maps to this name. Consider changing the implementation of the ResolveName method on your DataContractResolver to return a non-null value for name 'ConcurrencyBehavior' and namespace 'http://schemas.microsoft.com/xrm/7.1/Contracts'.'. Please see InnerException for more details.
After few searchs, I found 2 possible causes :
Enable Proxy type : the fact is I have the code to do that. So this couldn't help me.
_serviceProxy.EnableProxyTypes();
Version of SDK : I saw some answers about the fact that the SDK version 7.0 can cause this problem. The fact is that I am using the version 7.1 and I also try with the latest 7.1.1. I use this DLL's : Microsoft.Xrm.Client, Microsoft.Xrm.Sdk, Microsoft.Crm.Sdk.Proxy
Type of this element : I also try with a basic string as datatype. There is still problem of serealization.
None of these ideas solve my problem and right now, I do'nt really know where I am suppose to look into to solve fix this problem.
Also the problem might be unknown types. It's important to enable proxy types on OrganizationServiceProxy. It solved my issue with similar error
using (OrganizationServiceProxy proxy = new OrganizationServiceProxy(organizationUri, null, credentials, null))
{
proxy.EnableProxyTypes();
}
Not 100% what the issue is but I would suggest trying the following to see if it helps.
Regenerate your proxy, it might be a case that your proxy is out of date which is why the deserializer has no knowledge of any type that maps to this name.
Try using late bound just to see if that works, help to narrow things down if there is a problem in the early bound code. For example:
Entity account = new Entity("account");
account.Id = new Guid("");
account["new_link"] = "your value";
service.Update(account);
Break point the code and see what values are being updated on the account objects, e.g. make sure another attribute doesn't have an odd value.
I will share my solution to this problem, when using own created WCF services, which are using generated models from CRM.
When referencing the WCF service in other project using VS 2017, there are some options in the Add Service Reference window: press "Advanced..." and uncheck Reuse types in referenced assemblies
Hope it helps someone.
I have solved this problem by updating the referece Microsoft.Xrm.Tooling.Connector
It turned out that I was using an older version which did not match with others SDK references, but it did not crash when building the program.
You can use NuGet to get that assembly.
This is the project's URL:
https://learn.microsoft.com/es-es/dotnet/api/microsoft.xrm.tooling.connector?view=dynamics-xrmtooling-ce-9

WCF DataContractSerializer and XAML Namespaces

I am sending an object to a WCF service that contains a Windows Workflow definition, but the deserializer is faulting when trying to deserialize my custom activities.
This was previously working when I had the activities' namespaces defined in the form of:
xmlns:tta="clr-namespace:MyNamespace;assembly=MyAssembly"
but for maintainability reasons I have now mapped my activity namespaces to a XAML namespace using assembly attributes:
[assembly: XmlnsPrefix("http://schemas.product.com/activities/", "tta")]
[assembly: XmlnsDefinition("http://schemas.product.com/activities/", "MyNamespace")]
Thus my xaml namespace looks like: xmlns:tta="http://schemas.thacktech.com/activities/"
And my activity declared as: <tta:Naptime />
Because of this change, I now recieve NetDispatcherFaultException which reads:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:job. The InnerException message was 'Element 'http://schemas.datacontract.org/2004/07/System.Activities:Activity' contains data from a type that maps to the name 'Naptime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null:MyNamespace.Naptime'. The deserializer has no knowledge of any type that maps to this name. Consider changing the implementation of the ResolveName method on your DataContractResolver to return a non-null value for name 'MyNamespace.Naptime' and namespace 'Naptime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.'. Please see InnerException for more details.
Questions:
Why does the deseralizer succeed with type resolution when using the clr-namespace syntax, but fail when using the url-style syntax for a namespace declaration?
It looks like the type resolver is completely misinterpreting the type, listing the class name as the namespace. Why would it do this?
How do I properly implement this?
Thanks!

MVC Deserialization Error

Okay. This is my company's customer portal, it's an MVC 2 project. We have a back end SAP system that the portal draws data from. But it does not directly hit SAP, it sends an xml request to a VB app that gets the data and sends it back in an xml response. There is an interface IRequest that all the various requests implement examples would be CustomerNumberRequest, CompanyNameRequest, etc. These all implement the method ToXml which as the name suggests simply builds xml to send. All of the existing requests work fine. (Let me preface this by saying that I inherited this project and the guy who wrote it is no longer with us) I am now trying to send a request to get the Rep Groups from SAP. I basically copied one of the other requests verbatim, making the necessary tweaks to send the appropriate request. But it keeps failing with error messages that I don't understand:
The formatter threw an exception while
trying to deserialize the message:
There was an error while trying to
deserialize parameter
http://tempuri.org/:request. The
InnerException message was 'The
deserializer cannot load the type to
deserialize because type
'XXXXX.CustomerPortal.Domain.RepGroupRequest'
could not be found in assembly
'XXXXX.CustomerPortal.Domain,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null'. Check that the
type being serialized has the same
contract as the type being
deserialized and the same assembly is
used.'. Please see InnerException for
more details.
This error happens right at _communicationService.ProcessRequest(request); (shown below) It does not enter the ProcessRequest method it just tries to create a NetDataContractSerializer here:
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new NetDataContractSerializer();
}
and then it dies. These are the methods being called:
private void PopulateRepGroups()
{
List<string> repGroups = new List<string>();
RepGroupRequest request = new RepGroupRequest();
foreach (RepGroup repGroup in _repService.GetRepGroups(request))
repGroups.Add(repGroup.RepGroupName);
ViewData["RepGroups"] = new SelectList(repGroups);
}
public List<RepGroup> GetRepGroups(RepGroupRequest request)
{
string response = _communicationService.ProcessRequest(request);
return RepGroupResponseFactory.GetRepGroupResponse(response);
}
Can anybody tell me what this error message is telling me? It says the type cannot be found but the type should be IRequest (that's what it says when the CreateSerializer is hit) which is used all over this. I'm clearly lost, please help!
Quoting your exception
Check that the type being serialized has the same contract as the type being deserialized and the same assembly is used
Check the version of the library on both ends that CustomerPortal.Domain.RepGroupRequest resides in to make sure they are the same version exactly.

Problem with c# webservice, referencing a method and a type

I have run into a bit of a problem, well not sure if it is a problem, but would like some advice.
I have developed a c# webservice in vs2010 and when I debug the service i get this error in my browser
The XML element 'VoucherResponse' from namespace 'http://test.org/' references a method and a type. Change the method's message name using WebMethodAttribute or change the type's root element using the XmlRootAttribute.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The XML element 'VoucherResponse' from namespace 'test.org' references a method and a type. Change the method's message name using WebMethodAttribute or change the type's root element using the XmlRootAttribute.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Now looking at my code in at the actual class "VoucherResponse" i have,
public class VoucherResponse : AResponse
{
public Voucher Voucher { get; set; }
}
And the Voucher object looks like this
public class Voucher
{
public string PIN { get; set; }
public string Serial { get; set; }
public string Batch { get; set; }
}
Now in one of my web methods I return the VoucherResponse and I am assuming that this error occurs when it is reflected through and checked.
Has anyone had a similar problem with this before, or can anyone give me some advice on this?
Thanks
I found another case that raises the error! Here's my code:
[WebMethod]
public CheckUpdateResponse CheckUpdate()
{
...
}
Ok, let me explain: CheckUpdateResponse is a structure I defined in my code, CheckUpdate() is a method. So, in the WSDL .NET add automatically a Response suffix to the method name CheckUpdate.
Et voilĂ : it finds a duplicate element and gives the error "Change the method's message name using WebMethodAttribute..."
Solution? I renamed the returned type from CheckUpdateResponse to CheckUpdateResult and now everything works fine!
I hope this will help someone! I lost a lot of time on this...
Apparently, SOAP cannot handle methods that have the same name as their return type.
You can fix it by reading the error, and acting accordingly:
public class VoucherResponse
{
[WebMethod(MessageName="TheVoucher")]
public Voucher Voucher{get; set;}
}
I had the same issue, but in my case; the application that I developed is web service client, so I don't have control on changing the WSDL\Schema.
The problem was that I had one web service with 17 operations, all of them are returning the same complex type, I got the mentioned error due to deserialization of the return type, because .Net is wrapping the return type for each output, and the serializer is throwing error:
The XML element 'XYZ' from namespace 'ABC' references a method and a type. Change the method's message name using WebMethodAttribute or change the type's root element using the XmlRootAttribute.
Solution:
I opened Reference.cs file, removed all wappered return type generated classes, and kept only one, then changed its class name to be generic, not related to the operation, it worked for me.

WCF AddServiceReference causing custom tool error, not producing proxy

A problem with "Add Service Reference", and actually with SvcUtil over all its features.
In order to reproduce you just need to add an OperationContract with argument or returning the following class :
[XmlSchemaProvider("MySchema")]
public class MyStructure : IXmlSerializable
{
private XmlElement e;
private static void Func(object o, ValidationEventArgs args)
{
}
public static XmlQualifiedName MySchema(XmlSchemaSet xs)
{
//xs.XmlResolver = new XmlUrlResolver();
XmlSchema s = XmlSchema.Read(new XmlTextReader(new StringReader("<?xml version=\"1.0\"?><xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"><xs:complexType name=\"MyStructure\"><xs:sequence><xs:any /></xs:sequence></xs:complexType></xs:schema>")), null);
xs.Add(s);
return new XmlQualifiedName("MyStructure");
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
XmlDocument doc = new XmlDocument();
e = (XmlElement)doc.ReadNode(reader);
}
public void WriteXml(XmlWriter writer)
{
e.WriteTo(writer);
}
#endregion
}
The result is that when you use AddWebReference or AddSerivceReference without a reference to the class library containing the MyStructure type, everything will be fine ad you will get an xmlElement representation at the auto created proxy.
However, when you have a reference you will get the following warning :
================
Warning 1 Custom tool warning: Cannot import wsdl:portType
Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter
Error: Referenced type 'ServiceLibrary.MyStructure, ServiceLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' with data contract name 'MyStructure' in namespace '' cannot be used since it does not match imported DataContract. Need to exclude this type from referenced types.
XPath to Error Source: //wsdl:definitions[#targetNamespace='http://tempuri.org/']/wsdl:portType[#name='IService1'] \Projects\WCFSample\WCFExample\TestAddReference\Service References\ServiceReference1\Reference.svcmap 1 1 TestAddReference
======================
And no proxy will be generated for you.
Now, the internet is full with descriptions of this when you have a generic DataContract, and/or using IsReference attribute.
This is a much serious problem, since any non-typed data will do this problem.
Could not find any way to solve the problem. What if I want to know the type at the client side, by sharing the class library of the contracts ?
This type of exception generally means there is at least one difference in the type contracts generated by the service as compared to the referenced types (as the message indicates!). But it may not be obvious at first glance, as I found out. Make sure all nested and referenced types are up to date with the server. In my case, nested types were updated on the server. I thought I had updated by locally referenced assembly (and the shared reference types) but I missed some. It took close examination to find the culprit.
See additional information in this question
I have a suggestion:
I had similar errors, including:
the .svcmap file cannot be found. It may have been moved or deleted. To generate a new .svcmap file, delete the service reference and add it again.
And at that point, no way to delete the service reference unless I close VS2010 and open it again.
The situation is: my WCF service is running, I programmatically added a Description.ServiceMetadataBehavior at an HTTP address that I define.
In VS2010, I try to add a service reference at the HTTP address, I see my service, I add the reference, and voila, errors and warning.
The problem: my HTTP address is containing some key words that WCF doesn't like. Specifically the word COM (it breaks with LPT too).
So my solution: modify my HTTP address not to have the word COM. It worked for me.
If the service is hosted over HTTPS, go into the server's IIS Manager. Under "SSL Settings" for the site, make sure "Require SSL" is checked, and check the Client Certificates radio button for "Accept".

Categories