.NET 4.5.1 WCF Serialization exception - wcf

Our LOB application is a client server application which uses CSLA business objects, those business objects are being serialized using the NetDataContractSerializer. The server side is running on WCF and the client has endpoints.
This all works when the client software is running from Windows 7 or Windows 8 having .NET 4.5 installed.
When running the client software on Windows 8 or Windows 8.1 with the latest .NET 4.5.1 Framework the following exception occurs.
The formatter threw an exception while trying to deserialize the
message: There was an error while trying to deserialize parameter
http://ws.lhotka.net/WcfDataPortal:FetchResult. The InnerException
message was 'Error in line 1 position 11619. 'Element'
'm_serializationArray' from namespace
'http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not
expected. Expecting element 'm_keyRehashCount'.'. Please see
InnerException for more details.
The most inner exception is
Error in line 1 position 11619. 'Element' 'm_serializationArray' from
namespace 'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
is not expected. Expecting element 'm_keyRehashCount'.
I cannot find anything about this on stackoverflow or on google, i have posted this same question on the CSLA forums and perhaps i should also post it on Connect. But maybe i'm lucky here?
I need some time to backup my development environment before i update the .NET Framework to 4.5.1
I can think of two possible solutions:
upgrade the 2008 server to .NET 4.5.1.
force the client software to use .NET 4.5
Is it possible to force the client software to use .NET 4.5 only?
Any other idea's?

I can reproduce this issue from my end. I would like to give a few facts to see if this would help you in the meantime.
NetDataContractSerializer is more restrictive than a DataContractSerializer as per the documentation.
The NetDataContractSerializer differs from the DataContractSerializer in one important way: the NetDataContractSerializer includes CLR type information in the serialized XML, whereas the DataContractSerializer does not. Therefore, the NetDataContractSerializer can be used only if both the serializing and deserializing ends share the same CLR types.
I believe the type ConcurrentDictionary in 4.5.1 has added a property or member variable named m_keyRehashCount which is not found in the 4.5 version of the ConcurrentDictionary. While trying to de-serialize this object on a 4.5.1 machine – the serializer expects this missing property resulting in this exception.
<m_keyRehashCount>0</m_keyRehashCount>
Here are a few ways to solve this problem:
Upgrade your server machine as well to 4.5.1. .net 4.5.1 is a free upgrade to .net 4.5 which also has fixes for some compat issues found in .net 4.5.
Use DataContractSerializer instead of NetDataContractSerializer as this
does not expect the exact same CLR types at both serializing and
deserializing ends.
Change to use Dictionary instead
of a ConcurrentDictionary as I see this type works
fine.

If you have previously serialized objects (serialized with pre 4.5.1) which contain ConcurrentDictionary you can deserialize it in 4.5.1 using the following example.
This example only help deserializing already serialized ConcurrentDictionary objects by creating new class which can deserialize using the ConcurrentDictionary serialization XML, see also other answers.
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using ClassLibrary1.Model;
namespace SerializaerDesrializer
{
[DataContract]
public class CompositeDictionaryHolder
{
// Old serialized data member:
//[DataMember]
//private MyConcurrentDictionary<int, string> _concuurentDictionary = new MyConcurrentDictionary<int, string>();
private ConcurrentDictionary<int, string> _concuurentDictionaryInternal = new ConcurrentDictionary<int, string>();
[DataMember]
private InternalArray _concuurentDictionary;
public CompositeDictionaryHolder()
{
// Just an example:
_concuurentDictionaryInternal.TryAdd(1, "1");
_concuurentDictionaryInternal.TryAdd(2, "2");
_concuurentDictionaryInternal.TryAdd(3, "3");
}
/// <summary>
/// Get the data array to be serialized
/// </summary>
[OnSerializing]
private void OnSerializing(StreamingContext context)
{
// save the data into the serialization array to be saved
_concuurentDictionary = new InternalArray(_concuurentDictionaryInternal.ToArray());
}
/// <summary>
/// Construct the dictionary from a previously seiralized one
/// </summary>
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
_concuurentDictionaryInternal = new ConcurrentDictionary<int, string>(_concuurentDictionary.m_serializationArray);
}
}
[DataContract(
Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public class InternalArray
{
public InternalArray()
{
}
public InternalArray(KeyValuePair<int, string>[] serializationArray)
{
m_serializationArrayInternal = serializationArray;
}
[DataMember]
public KeyValuePair<int, string>[] m_serializationArray
{
get { return m_serializationArrayInternal; }
set { m_serializationArrayInternal = value; }
}
private KeyValuePair<int, string>[] m_serializationArrayInternal;
}
}

Related

Properties of user-defined struct not deserialized in .NET Core 3.0 web API (works in .NET Core 2.2)

I have an ASP.NET Core web API project targeting .NET Core 3.0 with the following controller:
public class FooController : ControllerBase
{
[HttpPost]
public ActionResult Post(Foo foo) => Ok()
}
Foo is defined in a separate library as:
public struct Foo
{
public int Bar { get; }
public Foo(int bar) => Bar = bar;
}
I call the API from a console app with:
new HttpClient().PostAsJsonAsync("http://localhost:55555/api/foo", new Foo(1)).Wait();
When the controller method is entered, foo.Bar has the default value of 0. I expect it to be 1.
This used to work as expected in .NET Core 2.2. The JSON deserializer handles properties with private setters on structs via an overloaded constructor with parameter names matching the property names (case-insensitive).
This no longer work in .NET Core 3.0 with basic structs (EDIT: due to this as pointed out by Martin Ullrich). However, if I use a standard struct type such as DateTime, it works fine. Is there something additional I must now do to my struct that DateTime for instance already supports? I've already tried implementing ISerializable on Foo with the code below, but that didn't work.
public Foo(SerializationInfo info, StreamingContext context)
{
Bar = (int)info.GetValue("bar", typeof(int));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("bar", Bar, typeof(int));
}
Any help would be greatly appreciated.
The new System.Text.Json APIs do not support all the features that Newtonsoft.Json ("Json.NET") does, including deserialisation of read-only properties.
If you need this feature, switch to using Newtonsoft.Json as described in the Migrate from ASP.NET Core 2.2 to 3.0 Guide:
services.AddMvc()
.AddNewtonsoftJson();
or
services.AddControllers()
.AddNewtonsoftJson();
DateTime is already known by the System.Text.Json stack in 3.0 and there also is a JsonConverter<T> implementation for it: JsonConverterDateTime.
For creating custom converters and registering them for ASP.NET Core, see https://stackoverflow.com/a/57334833/784387

MyMessage<T> throws an exception when calling XmlSerializer

I am very new to nservicebus. I am using version 3.0.1, the last one up to date. And I wonder if my case is a normal limitation of NSB, I am not aware of.
I have an asp.net MVC application, I am trying to setup and in my global.asax, I have the following :
var configure = Configure.WithWeb()
.DefaultBuilder()
.ForMvc()
.XmlSerializer();
But I have an error with the XmlSerializer when dealing with one of my object:
[Serializable]
public class MyMessage<T> : IMessage
{
public T myobject { get; set; }
}
I pass trough :
XmlSerializer()
instance.Initialize(types);
this.InitType(type, moduleBuilder);
this.InitType(info2.PropertyType, moduleBuilder);
and then when dealing With T,
string typeName = GetTypeName(t);
typename is null and the following instruction :
if (!nameToType.ContainsKey(typeName))
ends in error. null value not allowed.
Is this some limitations to Nservicebus, or am I messing something up?
NServiceBus intentionally does not support generic message types to encourage you to make your message schema explicit.

Passing an Entity Framework Context object to WCF

I need to pass a Context object from EF into a WCF method.
Normally, I create the Context object in the WCF method and dispose of it right before the end of the method call which works just fine for most of my methods.
However, I need to pass the Context object (specifically the DBContext) over from the MVC controller to my specific WCF method because I have caching enabled for some lookup tables. I need this specific Context object passed over (the one I set in the Application_Start method of the Global.asax file) rather than what I do in the sentence above because I use this specific object for the SqlDependency. If I try and create the DBContext object brand new, I can't use the SqlDependency becuase I will get an error informing me that the SqlDependency needs to be enabled before the database call.
The problem is that I'm getting the following error (shortened for brevity) when I try and start my WCF Test Client tool which I know has something to do with not properly declaring a KnownType attribute (ie the DBContext object). Note that the WCF project compiles just fine. I need some help with this specific part since I have never used a KnownType in my WCF service. They have all been simple types (int, string, etc).
Error: Cannot obtain Metadata from http://localhost:8732/Design_Time_Addresses/YeagerTechWcfService/YeagerTechWcfService/mex
If this is a Windows (R) Communication Foundation service to which you
have access, please check that you have enabled metadata publishing at
the specified address. For help enabling metadata publishing, please
refer to the MSDN documentation at
http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange
Error URI:
http://localhost:8732/Design_Time_Addresses/YeagerTechWcfService/YeagerTechWcfService/mex
Metadata contains a reference that cannot be resolved:
I have the following OperationContract code in my WCF service:
[OperationContract]
IEnumerable<Category> GetCategories(YeagerTechEntities DbContext);
I have the following DataContract code in my WCF service:
namespace YeagerTechModel
{
[Serializable]
[DataContract(IsReference = true)]
[KnownType(typeof(YeagerTechEntities))]
public partial class Category
{
public Category()
{
this.Projects = new HashSet<Project>();
}
[DataMember]
public short CategoryID { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public virtual ICollection<Project> Projects { get; set; }
}
}
Finally, the following is my WCF method:
public IEnumerable<YeagerTechModel.Category> GetCategories(YeagerTechEntities DbContext)
{
//YeagerTechEntities DbContext = new YeagerTechEntities();
DbContext.Configuration.ProxyCreationEnabled = false;
IEnumerable<YeagerTechModel.Category> category = DbContext.Categories.Where(p => p.CategoryID > 0).AsCached("Categories").ToList();
//IEnumerable<YeagerTechModel.Category> category = DbContext.Categories.Where(p => p.CategoryID > 0);
CloseConnection(DbContext);
return category;
}
You need singleton object following registry / service locator pattern. This object will hold reference to your global objects. For example at application start you will fill this object with your context using SqlDependency and you will use the registry to access this context in your controller's actions and service's operations.
Anyway work with this very carefully. SqlDependency and EF doesn't play nice together because it will make your context long living. Long living context is in most cases anti-pattern. Never ever use that context for anything else then loading cached data. Don't use it for data modification or loading non cached relations! Load entities as non-tracked (AsNoTracking extension method on query) in the first query and turn off proxy creation and lazy loading for that context.
Also be aware that query in EF is always executed in the database. I'm not sure what your AsCached is supposed to do but I somehow doubt it will work. What you need is probably:
var category = DbContext.Categories.Local
.Where(p => p.CategoryID > 0)
.ToList();
I would not use SqlDependency with EF. I would use ADO.NET and SQL directly. For caching in EF I would check EF Caching provider to use second level cache which is in most cases enough.

WCF object reference methods missing

I have created a WCF service in my project and I have some classes on the server side that I use on the servers side and on the client side via reference.
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
namespace DataEntities
{
[DataContract]
public class PlanEntriesData
{
private ObservableCollection<entry> entries;
public PlanEntriesData()
{
entries = new ObservableCollection<Entry>();
}
[DataMember]
public ObservableCollection<Entry> Entries
{
get { return entries; }
set { entries = value; }
}
public string helloWorld()
{
return "hello";
}
}
}
The problem is on the client side the object has no helloWorld() method. Can anyone help me with how to get the methods ?
best regards
sushiBite
Methods are not sent, only properties. There is currently no way to supply the implementation details of a method across a WCF boundary on a DataContract.
If you want to be able to operate on an entity from the client in such a way, you will need to add the HelloWorld operation to your ServiceContract.
public IMyService
{
string HelloWorld(PlanEntriesData data);
}
I'd recommend a little bit of reading up on service orientation and WCF in general. I've found "Windows Communication Step-by-Step" to be a good read for beginners.
You may need to add an [OperationContract] in your WCF Host projects Interface and implement it in the service class itself to make it available to the clients.

Configuring the timeout for a WCF RIA Services call from a Silverlight 3 client

I'm using the WCF RIA Services Beta with Silverlight 3.0 and I want to be able to configure the timeout from the client. I know that the underlying technology is WCF and the default timeout seems to be 60 seconds as I would expect.
Is there an easy way to control this and other WCF settings?
My first thought is to try the DomainContext OnCreated hook point which was mentioned in the RIA Services Overview pdf file that was available prior to RIA Services going beta. The MSDN documentation for the DomainContext object no longer mentions the method although it is still there? I'm not sure if this is a case of the documentation lagging behind or an indication that I shouldn't use this extensibility point.
namespace Example.UI.Web.Services
{
public sealed partial class CustomDomainContext
{
partial void OnCreated()
{
// Try and get hold of the WCF config from here
}
}
}
http://blogs.objectsharp.com/CS/blogs/dan/archive/2010/03/22/changing-timeouts-in-wcf-ria-services-rc.aspx
Either one line after domain context creation:
((WebDomainClient<LibraryDomainContext.ILibraryDomainServiceContract>)this.DomainClient).ChannelFactory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 5, 0);
or a partial class
public partial class LibraryDomainContext
{
partial void OnCreated()
{
if(DesignerProperties.GetIsInDesignMode(App.Current.RootVisual))
((WebDomainClient<LibraryDomainContext.ILibraryDomainServiceContract>)this.DomainClient).ChannelFactory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 5, 0);
}
}
For reference the code below nearly works but you can't access a private member using reflection in Silverlight. Wouldn't have been happy with this hack though anyway. Interesting to note that there is a WebDomainClient contructor that takes a Binding parameter private WebDomainClient(Uri serviceUri, bool usesHttps, Binding binding) but the XML Comment for this states Private constructor. Should be made public once we have an end-to-end extensibility story on top of WCF. Looks like I'll have to wait a while before they get to exposing this kind of configuration to us.
public sealed partial class AppDomainContext
{
partial void OnCreated()
{
var webDomainClient = ((WebDomainClient<AppDomainContext.IAppDomainServiceContract>)this.DomainClient);
// Can I use reflection here to get hold of the Binding
var bindingField = webDomainClient.GetType().GetField("_binding", BindingFlags.NonPublic | BindingFlags.Instance);
// In Silverlight, the value of a private field cannot be access by using reflection so the GetValue call throws an exception
// http://msdn.microsoft.com/en-us/library/4ek9c21e%28VS.95%29.aspx
var binding = bindingField.GetValue(webDomainClient) as System.ServiceModel.Channels.Binding;
// So near yet so far!!
binding.SendTimeout = new TimeSpan(0,0,1);
}
}