MyMessage<T> throws an exception when calling XmlSerializer - nservicebus

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.

Related

ServiceStack AutoQuery Is Null for Asp.Net.Core and NullReferenceException thrown at CreateQuery

I've done the Plugins.Add(new AutoQueryFeature { MaxLimit = 100 }); and used it in startup Configure Method.
This is dto inherites QueryDb
I keep encountering AutoQuery is null and NullReferenceException thrown at AutoQuery.CreateQuery() Method. And CallStacks can not show ExternalCodes. I have no ideas where it gone wrong by referring to TechStacks Project.
The project references ServiceStack.Core 5.7.0
I'm able to get AutoQuery by using the below code.
var autoquery = TryResolve<IAutoQueryDb>()
None of your code samples show the 3 important things required for AutoQuery, the AutoQueryFeature plugin registration in your AppHost’s Configure(), the definition of your Service class that implements the Service base class, the public IAutoQueryDb AutoQuery { get; set; } public property.
If they’re configured correctly the IAutoQueryDb dependency should be injected.

Why can't NServiceBus create a proxy for my message when using XML serialization?

I've defined a message, IGetQuote, for use with NServiceBus. It's shown below, with the other types on which it depends;
public interface IGetQuote : ICommand
{
IRisk Risk { get; set; }
}
public interface IRisk
{
IProposer Proposer { get; }
}
public interface IProposer : IDriver
{
string Postcode { get; set; }
}
public interface IDriver
{
string Name { get; set; }
void DoSomething();
}
When using the fluent API to get an IBus, I get the following exception when calling CreateBus();
System.TypeLoadException: "Method 'DoSomething' in type 'Contracts.IProposer_impl' from assembly 'Contracts_impl, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.":"Contracts.IProposer__impl"
From what I understand of the way NServiceBus works, it's trying to create types that implement IGetQuote and any associated interfaces such as IProposer, in order to make the XML serialization work when the IGetQuote message is sent.
If I adjust my interfaces so that IProposer no longer inherits from IDriver, the problem goes away. My initial conclusion was that the DoSomething method must be the problem, but if I make IProposer inherit IDriver again, and move the DoSomething method onto IProposer, the exception is not thrown (although I do get a warning message "Interface IProposer contains methods and therefore cannot be mapped. Be aware that non-mapped interfaces can't be used to send messages").
So it seems like the exception occurs when you have a method declared on an interface, and that interface is extended by one of the types upon which the message type depends. It's almost like the dynamic proxy generation doesn't account for interface inheritance.
Does anyone know what is going on here?
The messages sent by NSB define the contract or schema between two endpoints. This does not include behaviour, but simply data. NSB will handle interface inheritance, but rightfully so it warns you about adding behvaviour to your interfaces.

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 with shared objects and derived classes on client

I have a WCF service and I'm sharing types with a client in a shared assembly.
If the client create a derived class will it be possible to pass back the derived type to the service so that I can read the added properties through reflection ?
I tried but having issues with KnownTypes since the service don't know how to deserialize the derived type.
[Serializable]
public abstract class Car : ICar
{........
//on the client :
[Serializable]
public class MyCar : Car
{......
when passing myCar to Service I get the exception complaining about knownType but I cant add this on the server since I wont know what the client will be sending through and I want to handle extra properties through reflection.
Possible to register client types as knowntypes at runtime ?
Is this maybe the solution ?
http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx
This is not possible. Both service and client has to know what types will be sent in messages. If you want to use known type you have to define that relation to parent type on the service.
Why do you need to know added properties on the server?
I think there is a way.
I vaguely remember that when I studied WCF, I met ExtensionData which should be a mechanism to get everything that does not match the serialization of the class. for example, if you enable ExtensionData and you are in this situation
//Server
public class GenericRQ
{
public string GenericProperty {get;set;}
}
public Service GenericService
{
Public void GenericMethod(GenericRQ RQ)
{
}
}
// client
Public class MoreSpecificRQ : GenericRQ
{
public string SpecificProperty {get;set;}
}
At
Public void GenericMethod(GenericRQ RQ)
{
// the serializer adds automatically in RQ.ExtensionData everything that has come and that does not match the class GenericRQ.
}
On how to enable ExtensionData you to easily search on the web

WCF DataContract Upcasting

I'm trying to take a datacontract object that I received on the server, do some manipulation on it and then return an upcasted version of it however it doesn't seem to be working. I can get it to work by using the KnownType or ServiceKnownType attributes, but I don't want to roundtrip all of the data. Below is an example:
[DataContract]
public class MyBaseObject
{
[DataMember]
public int Id { get; set; }
}
[DataContract]
public class MyDerivedObject : MyBaseObject
{
[DataMember]
public string Name { get; set; }
}
[ServiceContract(Namespace = "http://My.Web.Service")]
public interface IServiceProvider
{
[OperationContract]
List<MyBaseObject> SaveMyObjects(List<MyDerivedObject> myDerivedObjects);
}
public class ServiceProvider : IServiceProvider
{
public List<MyBaseObject> SaveMyObjects(List<MyDerivedObject> myDerivedObjects)
{
... do some work ...
myDerivedObjects[0].Id = 123;
myDerivedObjects[1].Id = 456;
myDerivedObjects[2].Id = 789;
... do some work ...
return myDerivedObjects.Cast<MyBaseObject>().ToList();
}
}
Anybody have any ideas how to get this to work without having to recreate new objects or using the KnownType attributes?
I think that your problem is that you are trying to send over a generic list.
It will work if you encapsulate the list in an object. That is create an object with a single public property which is the generic list.
You also need to make sure that all classes that are not used directly in the contract are marked as serializable.
If you want to return the derived objects then there will always be a round trip because the client and the service are separate. In order for the client to update its own list of MyBaseObjects it has to deserialize the list of MyDerivedObjects that came from the server.
The use of KnownType and/or ServiceKnownType is needed because this leads to the addition of that type information into WSDL, which is in turn used by the client to deserialize the messages to the correct type.
For starters, a useful tool for testing the scenario you've described: http://www.wcfstorm.com
You might try creating a DataContractSurrogate (IDataContractSurrogate) and returning your base type for the call to GetDataContractType. I'm not really sure that's how it was intended to be used so you still may be better of with "the extra work", but maybe I don't understand the scope of that extra work.
One of the problems with WCF (and .net remoting) is that it they tries to make “message passing” look like method calls.
This fall down when you try to use too many “oop” type designs.
The fact that the messages are
represented by .net classes, does not
make all of their behaviour like .net
class.
See this, and this, for more on the problem of Leaking Abstraction.
So you need to start thinking about message passing not object when designing your WCF interfaces, or you will hit lots of problems like this.