WCF Known Type error - wcf

I get this error when calling my service:
Server Error in '/' Application.
--------------------------------------------------------------------------------
Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: There was an error while trying to serialize parameter http://DSD.myCompany.net/DsdWebServices/2011/05/:config. The InnerException message was 'Type 'System.OrdinalComparer' with data contract name 'OrdinalComparer:http://schemas.datacontract.org/2004/07/System' is not expected. 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.
Source Error:
Line 130: passwordAttemptWindow="10"
Line 131: passwordStrengthRegularExpression=""
Line 132: type="DsdWebsite.Providers.DsdMembershipProvider, DsdWebsite.Providers" />
Line 133: </providers>
Line 134: </membership>
Source File: C:\Development\DSD Website\WebUI\web.config Line: 132
--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.5444; ASP.NET Version:2.0.50727.5420
The service is a data service for a membership provider. I created a MembershipUser DTO to move data back and forth across the service. It uses only standard classes: string, int, DateTime. I use Guid instead of object for the providerUserKey.
The interface for the service looks like this:
[ServiceContract(Namespace = "http://DSD.myCompany.net/DsdWebServices/2011/05/")]
[ServiceKnownType(typeof(MembershipUserDTO))]
[ServiceKnownType(typeof(NameValueCollection))]
[ServiceKnownType(typeof(Guid))]
[ServiceKnownType(typeof(DateTime))]
public interface IDsdMembershipProviderService
{
[OperationContract]
void Initialize(string name, NameValueCollection config);
[OperationContract]
MembershipUserDTO CreateUser(string username,
string salt,
string encodedPassword,
...
The DTO looks like this
namespace DsdWebsite.Services.Providers
{
[Serializable]
[DataContract]
[KnownType(typeof(Guid))]
[KnownType(typeof(DateTime))]
public class MembershipUserDTO
{
public MembershipUserDTO(string providerName, string userName, Guid providerUserKey, string email,
string passwordQuestion, string comment, bool isApproved, bool isLockedOut,
DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate,
DateTime lastPasswordChangedDate, DateTime lastLockoutDate,
string firstName, string lastName, string cellPhone, string officePhone,
string brokerId, bool isAdmin, bool mustChangePassword)
{
ProviderName= providerName;
UserName = userName;
ProviderUserKey= providerUserKey;
Email= email;
PasswordQuestion= passwordQuestion;
Comment= comment;
IsApproved=isApproved;
IsLockedOut= isLockedOut;
CreationDate= creationDate;
LastLoginDate= lastLoginDate;
LastActivityDate= lastActivityDate;
LastPasswordChangedDate = lastPasswordChangedDate;
LastLockoutDate=lastLockoutDate;
...
Finally, my web.config looks like this:
<membership
defaultProvider="DsdMembershipProvider"
userIsOnlineTimeWindow="15"
hashAlgorithmType=""> <providers>
<clear/>
<add
name="DsdMembershipProvider"
connectionStringName="DsdMembershipConnectionString"
enablePasswordRetrieval="true"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
applicationName="/DsdWebsite/"
requiresUniqueEmail="true"
passwordFormat="Encrypted"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""
type="DsdWebsite.Providers.DsdMembershipProvider,
DsdWebsite.Providers" />
</providers> </membership>
How can I determine what type or object is causing the error?
Thanks

Use following ServiceKnownTypeAttribute constructor to specify type of class (declaringType) containing the static method methodName that will return service known types:
public ServiceKnownTypeAttribute(
string methodName,
Type declaringType
)
Inside the aforementioned static method add all service known types that are already added (although I think you would do good without DateTime and Guid), and add System.OrdinalComparer as well.
The catch is that System.OrdinalComparer is internal class so you will have to get the type via reflection.
EDIT:
System.OrdinalComparer is part of mscorlib assembly. Basically you can get its type in a following manner:
Type[] types = typeof( string ).Assembly.GetTypes();
and then you can retrieve the wanted type by name (using Linq, add necessary using statements).
Type type = types.Where( x => x.FullName == "System.OrdinalComparer" );
Previous two line can be combined in one, for simplicity done using two lines.
If you need more details, just say.

Related

SerializationException when returning custom classes from a WCF service

I have the following classes...
public abstract class Fallible<T> {
}
public class Success<T> : Fallible<T> {
public Success(T value) {
Value = value;
}
public T Value { get; private set; }
}
The background to this can be found in a previous question of mine, but you don't need to read that post as the classes above are all that's needed to see the problem.
If I have a simplified WCF service call like this...
[OperationContract]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
...then when I try to call the service from the WPF app that consumes it (or the WCF test client), I get a CommunicationException exception...
There was an error while trying to serialize parameter :GetPatientResult. The
InnerException message was 'Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer 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 the serializer.'. Please
see InnerException for more details.
...with an inner SerializationException exception of...
Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer 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 the serializer.
I've tried adding [DataContract] to the class and [DataMember] to each property, as well as adding a [KnownType] attribute for all four classes involved, and adding a [ServiceKnownType] for each of them on the service contract, but nothing helps.
I've read countless answers to the same question, but have not found anything that works. My services return other custom classes, and they all get serialised without a problem.
Anyone able to explain what the problem is here? Please let me know if I've not supplied enough information.
Turns out all I needed to do was decorate the service method with [ServiceKnownType] attributes for the base type, and each derived type...
[OperationContract]
[ServiceKnownType(typeof(Fallible<Patient>)]
[ServiceKnownType(typeof(Success<Patient>)]
[ServiceKnownType(typeof(BadIdea<Patient>)]
[ServiceKnownType(typeof(Failure<Patient>)]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
Although it's a pain to have to add four attributes to every call, it works. I'd like to know if there is a way to combine them into one attribute, but at least I have a working service now.
Hope this helps someone.

MVC - Context always uses the default connection string

I am looking to pick up MVC after previously working with web forms and I have been doing the movie tutorial over at asp.net but I am having an issue that is utterly confusing.
I have 2 connection string in my web config:
<connectionStrings>
<add name="MovieDBContext"
connectionString="Data Source=(LocalDB)\(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Movies.mdf;Integrated Security=True"
providerName="System.Data.SqlClient" />
<add name="DefaultConnection" connectionString="Data Source="(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-MvcMovie-20160408044847.mdf;Initial Catalog=aspnet-MvcMovie-20160408044847;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
I then have my context (Note I have tried setting the connection string here too after another answer on stack although I believe it should do it automatically if the context name is the same as the connection string name
public class MovieDBContext : DbContext
{
public MovieDBContext() : base("MovieDBContext"){ }
public DbSet<Movie> Movies { get; set; }
}
Whatever I do it uses the default connection string rather than the MovieDbContext connection string and for the life of me I cant work out why. If I set the data source of the default connection string to the datasource of the moviedbcontext one it works as it should and connects to the right database but I cant work out why it will ONLY use the default one (I have even tried changing the names of the connection string and the context to no avail)
Any help appreciated
Cheers
Try commenting the call to the base constructor in your derived DbContext class and just let the default constructor be called. Be sure that your web.config entry for the connection is in the root web.config file of the application and that it conforms to the expected naming conventions (see further down for more info).
public class MovieDBContext : DbContext
{
//// comment the call to the base constructor
// public MovieDBContext() : base("MovieDBContext"){ }
public DbSet<Movie> Movies { get; set; }
}
The MSDN documentation at https://msdn.microsoft.com/en-us/library/gg679577%28v=vs.103%29.aspx provides information about the convention used to determine the database name.
protected DbContext()
Constructs a new context instance using conventions to create the name of the database to which a connection will be made. By convention the name is the full name (namespace + class name) of the derived context class. For more information on how this is used to create a connection, see the remarks section for DbContext.

NetTCP and binary transfer

I have a WCF Service with HTTP bindings which returns dataset on 500k size.
When using WCF default logging I can see the messages and data being transfered with each message
<system.serviceModel>
<!-- add trace logging -->
<diagnostics wmiProviderEnabled="true">
<messageLogging
logEntireMessage="true"
logMalformedMessages="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="3000"
/>
</diagnostics>
....
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add initializeData="c:\nettcpTestLOCALToTEST.xml" type="System.Diagnostics.XmlWriterTraceListener"
name="messages">
<filter type="" />
</add>
</listeners>
</source>
</sources>
</system.diagnostics>
Point is, I am looking for a way to reduce the traffic between server and client, and I have been told that NetTCP is transferring the data binary? Is that correct?
I have set up a test scenario with a NetTCPBinding and when I read the WCF on the client side, the Response Message includes the whole dataset schema and data in XML format. Is it just serialized so the can be written to a log, or was this message transfered binary?
Is the amount of data being transfered with a NetTCP binding smaller than with HTTPBinding? Is it text or binary?
thanks in advance
yes the message will be transfered binary but the Serializer (Datacontractserializer I assume) will serialize the data in XML format:
Use the DataContractSerializer class to serialize and deserialize instances of a type into an XML stream or document
DataContractSerializer
From the docu:
The NetTcpBinding generates a run-time communication stack by default, which uses transport security, TCP for message delivery, and a binary message encoding. This binding is an appropriate system-provided choice for communicating over an Intranet.
NetTcpBinding MSDN
If you opt to implement ISerializable you can use WCF too but you have to implement an DataContractResolver to resolve the types: if the client "knows" the Types (for example you put them into a dll and add them to the client-app) you can use the following example-code (sorry I only have this in F# around but you should find it easy to translate)
This should yield the serialization in more compact form.
type internal SharedTypeResolver() =
inherit System.Runtime.Serialization.DataContractResolver()
let dict = new Xml.XmlDictionary()
override this.TryResolveType(t : Type, declaredT : Type, knownTypeResolver : System.Runtime.Serialization.DataContractResolver, typeName : Xml.XmlDictionaryString byref, typeNamespace : Xml.XmlDictionaryString byref) =
typeNamespace = dict.Add(t.Assembly.FullName)
typeName = dict.Add(t.FullName)
true
override this.ResolveName(typeName : string, typeNamespace : string, declaredType : Type, knownTypeResolver : System.Runtime.Serialization.DataContractResolver) =
let res = knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null)
if res = null then Type.GetType(typeName + ", " + typeNamespace) else res
PS: found the same in C#:
public class SharedTypeResolver : DataContractResolver
{
#region Overrides of DataContractResolver
///
/// Override this method to map a data contract type to an xsi:type name and namespace during serialization.
///
///
/// true if mapping succeeded; otherwise, false.
///
/// The type to map.The type declared in the data contract.The known type resolver.The xsi:type name.The xsi:type namespace.
public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
if (!knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace))
{
var dict = new XmlDictionary(); // nice trick to get the right type for typeName
if (type != null)
{
typeNamespace = dict.Add(type.Assembly.FullName);
typeName = dict.Add(type.FullName);
}
else
{
typeNamespace = dict.Add("noAss");
typeName = dict.Add("noType");
}
}
return true;
}
///
/// Override this method to map the specified xsi:type name and namespace to a data contract type during deserialization.
///
///
/// The type the xsi:type name and namespace is mapped to.
///
/// The xsi:type name to map.The xsi:type namespace to map.The type declared in the data contract.The known type resolver.
public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
{
return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ??
Type.GetType(typeName + ", " + typeNamespace);
}
(Please note: stackoverflow don't like the assignmentoperator "<-" from F# and i don't know how to circumvent - therefore I used "=")
oh well - I guess I have to say how to add those resolvers to your host:
private static void AddResolver(OperationDescription operationDescription)
{
if (operationDescription == null)
throw new ArgumentNullException();
var serializationBehavior = operationDescription.Behaviors.Find();
if (serializationBehavior == null)
{
serializationBehavior = new DataContractSerializerOperationBehavior(operationDescription);
operationDescription.Behaviors.Add(serializationBehavior);
}
serializationBehavior.DataContractResolver = new SharedTypeResolver();
}
use this with:
var contrDescription = _host.Description.Endpoints[0].Contract;
var description= contrDescription.Operations.Find("MyServiceMethod");
AddResolver(description);
replacing "MyServiceMethod" by the name of your service-method (on call per method or you iterate over all of them)

wcf netdatacontractserializer exception serialising idictionary with enumeration as key

I am using the NetDataContractSerialiser with WCF. This is working well with all our types being serialised. However, a service I am calling is generating the following exception
The formatter threw an exception while trying to deserialize the message:
There was an error while trying to deserialize parameter http://tempuri.org/:xmlServiceObjIN. The InnerException message was 'The deserializer cannot load the type to deserialize because type 'System.Collections.Generic.EnumEqualityComparer`1[[GrantEd.Common.DomainModel.Code.Enums.enumFundingParameterContextKey, GrantEd.Common.DomainModel.Code, Version=14.0.71.0, Culture=neutral, PublicKeyToken=null]]' could not be found in assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
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.
The class being serialised has a property defined as
public IDictionary<enumFundingParameterContextKey, string> Context { get; set; }
the declaration of the enum is
[Serializable]
public enum enumFundingParameterContextKey
{
[EnumMemberAttribute()]
ClientId = 0,
[EnumMemberAttribute()]
EntitlementDefinitionId = 1
}
which is defined in another assmebly.
When I replace the enumeration with int the class deserialises with no problems. Any ideas why using the enum would result the exception?
The reason for using NetDataContractSerializer was to for type information to be available and avoid having to use KnownType
Make the base type as non integer for your enum. e.g. a byte.
Example:
[Serializable] public enum enumFundingParameterContextKey : byte
{
[EnumMemberAttribute()]
ClientId = 0,
[EnumMemberAttribute()]
EntitlementDefinitionId = 1
}
Details are in my following blog post: dotnet-35-to-dotnet-40-enum
Try to mark enum with [DataContract] instead of [Serializable]. But it looks like the enum type is unknown at all on the client.

In the WCF web programming model, how can one write an operation contract with an array of query string parameters (i.e. with the same name)?

Using the WCF web programming model one can specify an operation contract like so:
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "SomeRequest?qs1={qs1}&qs2={qs2}")]
XElement SomeRequest1(string qs1, string qs2);
Now if we had to make a contract that accepts an array of parameters with the same name (in this case qs1) contract like so...
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "SomeRequest?qs1={qs1}&qs1={qs2}")]
XElement SomeRequest2(string qs1, string qs2);
We get the error message at run time when we make the invocation to the method:
the query string must have 'name=value' pairs with unique names. Note that the names are case-insensitive. See the documentation for UriTemplate for more details.
How does one define an HTTP service that exposes a resource with an array of parameters without resorting to a loosey-goosey interface?
I've implemented a simple custom QueryStringConverter so that you can make qs1 an string[] then have the query string variable be comma delimited (e.g. http://server/service/SomeRequest?qs1=val1,val2,val3,val4)
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml,
UriTemplate = "SomeRequest?qs1={qs1}")]
XElement SomeRequest2(string[] qs1);
First you need a class that inherits from WebHttpBehavior so that we can inject our custom QueryStringConverter:
public class CustomHttpBehavior : System.ServiceModel.Description.WebHttpBehavior
{
protected override System.ServiceModel.Dispatcher.QueryStringConverter GetQueryStringConverter(System.ServiceModel.Description.OperationDescription operationDescription)
{
return new CustomQueryStringConverter();
}
}
Then our CustomQueryStringConverter that handles string[] parameters:
public class CustomQueryStringConverter : System.ServiceModel.Dispatcher.QueryStringConverter
{
public override bool CanConvert(Type type)
{
if (type == typeof(string[]))
{
return true;
}
return base.CanConvert(type);
}
public override object ConvertStringToValue(string parameter, Type parameterType)
{
if (parameterType == typeof(string[]))
{
string[] parms = parameter.Split(',');
return parms;
}
return base.ConvertStringToValue(parameter, parameterType);
}
public override string ConvertValueToString(object parameter, Type parameterType)
{
if (parameterType == typeof(string[]))
{
string valstring = string.Join(",", parameter as string[]);
return valstring;
}
return base.ConvertValueToString(parameter, parameterType);
}
}
The last thing you need to do is create a behavior configuration extension so that the runtime can get an instance of the CustomWebHttpBehavior:
public class CustomHttpBehaviorExtensionElement : System.ServiceModel.Configuration.BehaviorExtensionElement
{
protected override object CreateBehavior()
{
return new CustomHttpBehavior();
}
public override Type BehaviorType
{
get { return typeof(CustomHttpBehavior); }
}
}
Now we add the element to our configuration extensions so that our CustomWebHttpBehavior is used, we use the Name of that extension instead of <webHttp /> in our behavior:
<system.serviceModel>
<services>
<service name="NameSpace.ServiceClass">
<endpoint address="" behaviorConfiguration="MyServiceBehavior"
binding="webHttpBinding" contract="NameSpace.ServiceClass" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="MyServiceBehavior">
<customWebHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="customWebHttp" type="NameSpace.CustomHttpBehaviorExtensionElement, MyAssemblyName" />
</behaviorExtensions>
</extensions>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
You can now also extend your CustomQueryStringConverter to handle other types that the default one doesn't, such as nullable value types.
NOTE: There is a bug logged at microsoft connect that directly relates to this code. The code does not actually work in almost all circumstances where you attempt to Query Convert different types.
http://connect.microsoft.com/VisualStudio/feedback/details/616486/bug-with-getquerystringconverter-not-being-called-by-webservicehost#tabs
Please make sure you read this carefully before wasting hours of your time creating custom REST query string converters that cannot possibly work. (Applies to Framework 4.0 and below).
To respond to your comment on my other answer:
You can do a wildcard parameter at the end of the querystring like
[WebGet(ResponseFormat = WebMessageFormat.Xml,
UriTemplate = "SomeRequest?qs1={*qs1}")]
XElement SomeRequest2(string qs1);
This way the qs1 string parameter will be the whole raw querystring after the qs1=, you could then parse that manually in your code.
The QueryStringConverter relies on the formatting of the querystring so doing something exactly how you want is not possible without possibly rewriting QueryStringConverter instead of the little overrides we did in the other answer.
From MSDN:
Wildcard segments must follow the following rules:
There can be at most one named wildcard segment for each template string.
A named wildcard segment must appear at the right-most segment in the path.
A named wildcard segment cannot coexist with an anonymous wildcard segment within the same template string.
The name of a named wildcard segment must be unique.
Named wildcard segments cannot have default values.
Named wildcard segments cannot end with “/”.
Be aware that in WCF 3.5 you must specify the full qualified assembly name in:
<extensions>
<behaviorExtensions>
<add name="customWebHttp" type="NameSpace.CustomHttpBehaviorExtensionElement, MyAssemblyName, NOT SUFFICIENT HERE" />
</behaviorExtensions>
</extensions>
Just like this: SampleService.CustomBehavior, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Otherwise you will get exception:
Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: Invalid element in configuration. The extension name 'CustomWebHttp' is not registered in the collection at system.serviceModel/extensions/behaviorExtensions.