WCF: Configuring Known Types - wcf

I want to know as to how to configure known types in WCF. For example, I have a Person class and an Employee class. The Employee class is a sublass of the Person class. Both class are marked with a [DataContract] attribute.
I dont want to hardcode the known type of a class, like putting a [ServiceKnownType(typeof(Employee))] at the Person class so that WCF will know that Employee is a subclass of Person.
Now, I added to the host's App.config the following XML configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="Person, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral,PublicKeyToken=null">
<knownType type="Employee, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral, PublicKeyToken=null" />
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
<system.serviceModel>
.......
</system.serviceModel>
</configuration>
I compiled it, run the host, added a service reference at the client and added some code and run the client. But an error occured:
The formatter threw an exception while
trying to deserialize the message:
There was an error while trying to
deserialize parameter
http://www.herbertsabanal.net:person.
The InnerException message was 'Error
in line 1 position 247. Element
'http://www.herbertsabanal.net:person'
contains data of the
'http://www.herbertsabanal.net/Data:Employee'
data contract. The deserializer has no
knowledge of any type that maps to
this contract. Add the type
corresponding to 'Employee' to the
list of known types - for example, by
using the KnownTypeAttribute attribute
or by adding it to the list of known
types passed to
DataContractSerializer.'. Please see
InnerException for more details.
Below are the data contracts:
[DataContract(Namespace="http://www.herbertsabanal.net/Data", Name="Person")]
class Person
{
string _name;
int _age;
[DataMember(Name="Name", Order=0)]
public string Name
{
get { return _name; }
set { _name = value; }
}
[DataMember(Name="Age", Order=1)]
public int Age
{
get { return _age; }
set { _age = value; }
}
}
[DataContract(Namespace="http://www.herbertsabanal.net/Data", Name="Employee")]
class Employee : Person
{
string _id;
[DataMember]
public string ID
{
get { return _id; }
set { _id = value; }
}
}
Btw, I didn't use class libraries (WCF class libraries or non-WCF class libraries) for my service. I just plain coded it in the host project.
I guess there must be a problem at the config file (please see config file above). Or I must be missing something. Any help would be pretty much appreciated.

I guess I have found the answer now.
The configuration file I posted above looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="Person, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral,PublicKeyToken=null">
<knownType type="Employee, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral, PublicKeyToken=null" />
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
<system.serviceModel>
.......
</system.serviceModel>
</configuration>
What I just added was, the Namespace of the Person class and the Employee class. And no need for the longer Version and Culture values.... The correct configuration should be:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="WCFWithNoLibrary.Person, WCFWithNoLibrary">
<knownType type="WCFWithNoLibrary.Employee, WCFWithNoLibrary" />
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
<system.serviceModel>
.......
</system.serviceModel>
</configuration>
Now it is shorter and makes more sense. But if 3rd party libraries are used, then adding version, culture, publickeytokens would be required.

I know this was answered a long time ago, but, another (maybe more obvious for future programmers) solution:
[KnownType(typeof(SubClass))]
public class BaseClass
Scott

I got this lengthy error message also in another case. I did use the KnownTypeAttribute and had successfully deployed an application which uses WCF.RIA to production. In the second release I added a new subtype, and added the necessary corresponding KnownTypeAttribute (the compiler did not accept it without this attribute - great). What the compiler did accept and what ran on my machine, did not run in production, however. Only in production I got the error mentioned above. Comparing all the uses of the existing subtypes and the new one revealed I had forgotten that WCF.RIA requires the name of the subtype to be used in a name of a method, like GetMySubTypes. So if you get this error after having added the attributes, see whether it's because of WCF.RIAs conventions.

Related

Use Configuration File To Specify Connection String To Define a Data Source in Unit Test for Data Driven Test CSV

The following code is defined in the test class. But i want to use DataSource("DataSourceSettingName") and app.config define.
<DeploymentItem("DataSets\\TestUserMainInput.csv")>
<DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\DataSets\\TestUserMainInput.csv", "TestUserMainInput#csv", DataAccessMethod.Sequential)>
Environment:
Visual Studio 2017
Microsoft.VisualStudio.TestTools.UnitTesting
.NET Framework 4.6.1
I already tried the following code. It failed.
<configSections>
<section name="microsoft.visualstudio.testtools" type="Microsoft.VisualStudio.TestTools.UnitTesting.TestConfigurationSection, Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</configSections>
<connectionStrings>
<add name="MyExcelConn" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\DataSets\TestUserMainInput.csv;Extended Properties='text;HDR=Yes;FMT=Delimited'" providerName="System.Data.OleDb" />
</connectionStrings>
<microsoft.visualstudio.testtools>
<dataSources>
<add name="MainDataSource" connectionString="MyExcelConn" dataTableName="TestUserMainInput#csv" dataAccessMethod="Sequential"/>
</dataSources>
</microsoft.visualstudio.testtools>
Output --> Tests
Error Message
An exception occurred while calling the 'executor: // mstestadapter / v2' player: 'Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestSettings, Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter, Version = 14.0.0.0, Culture = neutral, PublicKeyToken The species could not be resolved for = b03f5f7f11d50a3a '.
Could anyone help me solve this?
There is no need to change the app.config
Just Create a new test project and add a class like this one.
The test iterates for all the csv rows. You need to place the csv in your solution and change it to copy local always.
[TestClass]
public class UnitTest1
{
public TestContext TestContext { get; set; }
private static TestContext _testContext;
[ClassInitialize]
public static void SetupTests(TestContext testContext)
{
_testContext = testContext;
}
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\DataSource\\teste.csv", "teste#csv", DataAccessMethod.Sequential), DeploymentItem("DataSource\\teste.csv"), TestMethod]
public void Testing()
{
Assert.AreEqual(TestContext.DataRow["user"], "myusername");
}
}
I found the answer in following thread:
https://dondeetan.com/2017/07/03/referencing-mstest-and-mstestv2-unit-testing-framework-through-namespace-aliasing/
MSTest (Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll) and MSTestV2 (Microsoft.VisualStudio.TestPlatform.TestFramework.dll) those assemblies have the exact same namespace.
The Issue: Reference both MSTest and MSTestV2 in the same test project using the C# but that there's no VB way of doing this.

Entlib Custom exception handler missing mappings

I implemented custom exception handler which works, except mappings from xml configuration policy. Those mapping works with standard Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler
My implementation
[ConfigurationElementType(typeof(CustomHandlerData))]
public class IdentityFaultContractExceptionHandler : IExceptionHandler
{
public IdentityFaultContractExceptionHandler(NameValueCollection attributes)
{
}
public IdentityFaultContractExceptionHandler(Type faultContractType, NameValueCollection attributes)
{
}
public IdentityFaultContractExceptionHandler(Type faultContractType, string exceptionMessage, NameValueCollection attributes)
{
}
public IdentityFaultContractExceptionHandler(IStringResolver exceptionMessageResolver, Type faultContractType, NameValueCollection attributes)
{
}
public Exception HandleException(Exception exception, Guid handlingInstanceId)
{
return new Exception();
}
and part of the configuration
<add name="All Exceptions" type="System.Exception, mscorlib" postHandlingAction="ThrowNewException">
<exceptionHandlers>
<add type="MyClass.IdentityFaultContractExceptionHandler, MyClass" exceptionMessage="An error occurred in the service." faultContractType="MyClass.UnexpectedServerFault, MyClass" name="Fault Contract Exception Handler" >
<mappings>
<add source="{Message}" name="Message" />
</mappings>
</add>
</exceptionHandlers>
</add>
When I remove mappping node service works, when I add, then I got error : unrecognize element mappings.
If you are using a CustomHandlerData attribute then your configuration needs to use XML Attributes which then get passed in as a NameValueCollection to the custom handler constructor. If you want to have custom XML then you will have to use Full Design-time Integration. If you want to go down that road then you should look at the FaultContractExceptionHandlerData source code since your code would probably be quite similar.

Is there a way to pass parameters to a custom Service Behavior through configuration

I have multiple WCF services hosted in IIS to which I'm applying the same custom service behavior. I'm looking for a way to pass several parameters to the behavior through configuration, such as in behaviorExtensions or behavior elements.
If it helps, I'm also adding custom message inspector in ApplyDispatchBehavior, so I will need to pass parameters to the inspector:
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
new ValidatingMessageInspector(<custom parameters>));
}
}
}
Would just creating a configuration section in web.config with the parameters be valid? If so you can just read the config there and apply it, or even just use appSettings if the parameters are basic.
For example, if you have few parameters of basic types, maybe a simple approach could be:
<appSettings>
<add key="Shared.CommonParameter" value="A value" />
<add key="Service1.OneParameter" value="False" />
<add key="Service1.AnotherParameter" value="Some Value" />
<add key="Service2.ADifferentParameter" value="42" />
</appSettings>
That way it would be easy to differentiate what setting belongs to which service (notice the service name prefix in the key), and also have some shared parameters if needed.
If you need something more complex in structure you might want to look into defining custom configuration sections for each service, as is shown here: http://msdn.microsoft.com/en-us/library/2tw134k3%28v=vs.140%29.aspx
But that might be overkill, depending on your needs and expected flexibility.

Logging SQL statements of Entity Framework 5 for database-first aproach

I'm trying to use Entity Framework Tracing Provider to log the SQL staments generated.
I changed my context class to something like this:
public partial class MyDBContext: DbContext
{
public MyDBContext(string nameOrConnectionString)
: base(EFTracingProviderUtils.CreateTracedEntityConnection(nameOrConnectionString), true)
{
// enable sql tracing
((IObjectContextAdapter) this).ObjectContext.EnableTracing();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
//DbSets definition....
}
But this doesn't log the SQL statements on the Output window...
Should I had something more in the class or in web.config file? (I'm working on a ASP.NET MVC 4 project)
I using the solution in the following post:Entity Framework 4.1 - EFTracingProvider
but I made some changes that I don't know if they are important:
The class is partial instead of abstract, and the constructor is public instead of protected...
What am I missing?
After modifying your code, you need to enable tracing in your web.config like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.diagnostics>
<sources>
<source name="EntityFramework.NorthwindEntities" switchValue="All" />
</sources>
</system.diagnostics>
</configuration>
The name of your TraceSource should be your context name prefixed with 'EntityFramework'.
Make sure that you disable tracing when you deploy your application to production by setting the switchValue to Off.

Why is my WCF Data Services method not appearing in the OData collections list?

When I view the root of my WCF Data Services service (http://localhost/MyService.svc/) in a browser I see this:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<service xml:base="http://localhost/MyService.svc/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">
<workspace>
<atom:title>Default</atom:title>
</workspace>
</service>
I would expect to see a list of collections.
When I go to the $metadata URL I see this:
<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="1.0">
<Schema Namespace="MyApp" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2007/05/edm">
<ComplexType Name="Package">
<Property Name="Id" Type="Edm.String" Nullable="true" />
</ComplexType>
</Schema>
<Schema Namespace="MyApp" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2007/05/edm">
<EntityContainer Name="PackageService" m:IsDefaultEntityContainer="true">
<FunctionImport Name="GetQueryablePackages" ReturnType="Collection(MyApp.Package)" m:HttpMethod="GET" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Why might my GetQueryablePackages collection not be appearing?
I'm using these access settings:
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
Service operations (the function import in the EDM) is not exposed in the service document. Only entity sets are exposed there.
If you want your data to be exposed in the service document make an entity set out of it. Depending on the provider model this differs. Typically it means exposing a property of type IQueryable on your context class. Note that T has to be an entity type (must have a key).
Can you share the context definition where you have defined the IQueryable <> properties. There are 2 things that come to my mind: First the properties must be of type IQueryable<> or some type that derives from it. Second, the element type refered by the IQueryable<> must be an entity type i.e. they must have key properties declared in them.
Hope this helps.
Thanks
Pratik
Or you can create an extension method like this:
public static class TestEntitiesExtensions
{
public static IEnumerable<Package> GetQueryablePackages(this TestEntities context)
{
var uri = new Uri(context.BaseUri, "GetQueryablePackages");
return context.Execute<Package>(uri);
}
}