List<dynamic> on NServiceBus Message - nservicebus

I'm using NServiceBus to power the back-end of an application with a
JavaScript client. Therefore, we have lots of cases where our commands
really want dynamic lists (object arrays in JS, List in C#). e.g.:
JSON:
{
"listProperty" : [
{
"propertyA" : "value",
"propertyB" : "valueB"
},
{
"propertyQ" : "valueQ"
}
]
}
C#:
class TheCommand : IMessage {
public List<dynamic> ListProperty {get; set;}
}
Is there a way to do this with NServiceBus?
----- Experimentation Results -----
Some experimentation with the XML Serializer from NServiceBus shows that
it does not understand the dynamics:
<TheCommand>
<ListProperty>
<Object>
</Object>
</ListProperty>
</TheCommand>
They simply serialize (and deserialize) as Objects, with no properties.
(This a bit of a cross-post with the yahoo group as well.)

With our JS clients we use a set of REST style services that handle serialization and passing messages to NSB. We pass variable length arrays all the time.
In reference to dynamic structures all together, NSB requires a message to be formatted specifically to activate its handlers. It may be a good idea to implement your own serializer. You must implement NServiceBus.Serialization.IMessageSerializer. Beyond that you must also be able to tell NSB to use that serializer and you may have your own custom configuration that goes along with it. Take a look at the class ConfigureXmlSerializer.
I also just saw that in the 3.0 branch there is a JSON/BSON serializer implemented. I've never used it, but it may meet your needs.

Related

Rebus with RabbitMQ accept requests from Python

I am setting up a .NET core service that is reading from RabbitMQ using Rebus. It seems that the request placed in RabbitMQ needs to have the .NET object namespace information. Is there a way to work around this. For example if I had a service written in Python placing items on the queue would it be possible to read and process these requests. It seems every time I test and try to send something besides the .NET object I get an exception.
System.Collections.Generic.KeyNotFoundException: Could not find the key 'rbs2-content-type' - have the following keys only: 'rbs2-msg-id'
It depends on which serializer, you're using in the receiving end.
By default, Rebus will use its built-in JSON serializer with a fairly "helpful" setting, meaning that all .NET types names are included. This enables serialization of complex objects, including abstract/interface references, etc.
This serializer requires a few special headers to be present, though, e.g. the rbs2-content-type header, which it uses to verify that the incoming message presents itself as JSON (most likely by having application/json; charset=utf-8 as its content type).
If you want to enable deserialization of messages from other platforms, I suggest you provide the necessary headers on the messages (which – at least with Rebus' built-in serializer – also includes a .NET type name of the type to try to deserialize into).
Another option is to install a custom serializer, which is a fairly easy thing to do – you can get started by registering your serializer like this:
Configure.With(...)
.(...)
.Serialization(s => s.Register(c => new YourCrazySerializer()))
.Start();
which you then implement somewhat like this:
public class YourCrazySerializer : ISerializer
{
public async Task<TransportMessage> Serialize(Message message)
{
var headers = message.Headers.Clone();
// turn into byte[] here
//
// possibly add headers
return new TransportMessage(headers, bytes);
}
public async Task<Message> Deserialize(TransportMessage transportMessage)
{
var headers = transportMessage.Headers.Clone();
// turn into object here
//
// possibly remove headers
return new Message(headers);
}
}
As you can see, it's pretty easy to modify Rebus to accept messages from other systems.

Subtype of shared data contract

Following advices from people on the internet about service references, I got rid of them now and split the service/data contracts into a common assembly accesible by both the server and the client. Overall this seems to work really well.
However I’m running into problems when trying to use custom objects, or rather custom subtypes, in the service. Initially I wanted to define only interfaces in the common assembly as the contract for the data. I quickly learned that this won’t work though because the client needs a concrete class to instantiate objects when receiving objects from the service. So instead I used a simple class instead, basically like this:
// (defined in the common assembly)
public class TestObject
{
public string Value { get; set; }
}
Then in the service contract (interface), I have a method that returns such an object.
Now if I simply create such an object in the service implementation and return it, it works just fine. However I want to define a subtype of it in the service (or the underlying business logic), that defines a few more things (for example methods for database access, or just some methods that work on the objects).
So for simplicity, the subtype looks like this:
// (defined on the server)
public class DbTestObject : TestObject
{
public string Value { get; set; }
public DbTestObject(string val)
{
Value = val;
}
}
And in the service, instead of creating a TestObject, I create the subtype and return it:
public TestObject GetTestObject()
{
return new DbTestObject("foobar");
}
If I run this now, and make the client call GetTestObject, then I immediately get a CommunicationException with the following error text: “The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:09:59.9380000'.”
I already found out, that the reason for this is that the client does not know how to deserialize the DbTestObject. One solution would be to declare the base type with the KnownTypeAttribute to make it know about the subtype. But that would require the subtype to be moved into the common assembly, which is of course something I want to avoid, as I want the logic separated from the client.
Is there a way to tell the client to only use the TestObject type for deserialization; or would the solution for this be to use data transfer objects anyway?
As #Sixto Saez has pointed out, inheritance and WCF don't tend to go together very well. The reason is that inheritance belongs very much to the OO world and not the messaging passing world.
Having said that, if you are in control of both ends of the service, KnownType permits you to escape the constraints of message passing and leverage the benefits of inheritance. To avoid taking the dependency you can utilise the ability of the KnownTypeAttribute to take a method name, rather than a type parameter. This allows you to dynamically specify the known types at run time.
E.g.
[KnownType("GetKnownTestObjects")]
[DataContract]
public class TestObject
{
[DataMember]
public string Value { get; set; }
public static IEnumerable<Type> GetKnownTestObjects()
{
return Registry.GetKnown<TestObject>();
}
}
Using this technique, you can effectively invert the dependency.
Registry is a simple class that allows other assemblies to register types at run-time as being subtypes of the specified base class. This task can be performed when the application bootstraps itself and if you wish can be done, for instance, by reflecting across the types in the assembly(ies) containing your subtypes.
This achieves your goal of allowing subtypes to be handled correctly without the TestObject assembly needing to take a reference on the subtype assembly(ies).
I have used this technique successfully in 'closed loop' applications where both the client and server are controlled. You should note that this technique is a little slower because calls to your GetKnownTestObjects method have to be made repeatedly at both ends while serialising/deserialising. However, if you're prepared to live with this slight downside it is a fairly clean way of providing generic web services using WCF. It also eliminates the need for all those 'KnownTypeAttributes' specifying actual types.

Request/Response pattern in SOA implementation

In some enterprise-like project (.NET, WCF) i saw that all service contracts accept a single Request parameter and always return Response:
[DataContract]
public class CustomerRequest : RequestBase {
[DataMember]
public long Id { get; set; }
}
[DataContract]
public class CustomerResponse : ResponseBase {
[DataMember]
public CustomerInfo Customer { get; set; }
}
where RequestBase/ResponseBase contain common stuff like ErrorCode, Context, etc. Bodies of both service methods and proxies are wrapped in try/catch, so the only way to check for errors is looking at ResponseBase.ErrorCode (which is enumeration).
I want to know how this technique is called and why it's better compared to passing what's needed as method parameters and using standard WCF context passing/faults mechanisms?
The pattern you are talking about is based on Contract First development. It is, however not necessary that you use the Error block pattern in WCF, you can still throw faultexceptions back to the client, instead of using the Error Xml block. The Error block has been used for a very long time and therefore, a lot of people are accustom to its use. Also, other platform developers (java for example) are not as familiar with faultExceptions, even though it is an industry standard.
http://docs.oasis-open.org/wsrf/wsrf-ws_base_faults-1.2-spec-os.pdf
The Request / Response pattern is very valuable in SOA (Service Oriented Architecture), and I would recommend using it rather than creating methods that take in parameters and pass back a value or object. You will see the benefits when you start creating your messages. As stated previously, they evolved from Contract First Development, where one would create the messages first using XSDs and generate your classes based on the XSDs. This process was used in classic web services to ensure all of your datatypes would serialize properly in SOAP. With the advent of WCF, the datacontractserializer is more intelligent and knows how to serialize types that would previously not serialize properly(e.g., ArrayLists, List, and so on).
The benefits of Request-Response Pattern are:
You can inherit all of your request and responses from base objects where you can maintain consistency for common properties (error block for example).
Web Services should by nature require as little documentation as possible. This pattern allows just that. Take for instance a method like public BusScheduleResponse GetBusScheduleByDateRange(BusDateRangeRequest request); The client will know by default what to pass in and what they are getting back, as well, when they build the request, they can see what is required and what is optional. Say this request has properties like Carriers [Flag Enum] (Required), StartDate(Required), EndDate(Required), PriceRange (optional), MinSeatsAvailable(Option), etc... you get the point.
When the user received the response, it can contain a lot more data than just the usual return object. Error block, Tracking information, whatever, use your imagination.
In the BusScheduleResponse Example, This could return Multiple Arrays of bus schedule information for multiple Carriers.
Hope this helps.
One word of caution. Don't get confused and think I am talking about generating your own [MessageContract]s. Your Requests and Responses are DataContracts. I just want to make sure I am not confusing you. No one should create their own MessageContracts in WCF, unless they have a really good reason to do so.

WCF and member-method replacements

I have an object of the form:
public class Report
{
m_filter1;
m_filter2;
...
m_filtern;
AddFilter1(int a)
{
m_filter1 = /* some logic of filtering results using the value of a */
}
...
}
Also, a corresponding static method used to utilize the Report class:
public static List<Result> GetResults(Report r)
{
/* use r to query the DB and return an array of results */
}
As this method needs to be exposed using WCF, i must also make the class Report available for 'outside' (client) use, but its member-methods, which hide the internal plumbings, cannot be used in the WCF proxy class generated for it.
As i can't expose the private members of Report, how can i elegantly solve the problem of member-methods needed on the consuming side?
I thought of a service contract of the form:
public class ReportingService
{
Report m_report = new Report();
AddFilter1(int a)
{
m_report.AddFilter1(a);
}
...
}
i.e., to wrap the member-methods of the Report class using a single Report instance - but that puts a limitation of using a single, non thread-safe object shared by all the calls to the service.
Is there anything basic i'm missing here? i'm quite new to WCF, so i've probably overlooked an easy pattern of solving this out.
Thanks,
Harel
Well, as you've noticed - WCF only ever conveys data across the server-client link - and that's absolutely intentional. WCF handles serialized messages - data only. Think about it for a second: WCF is totally interoperable - your client could be a PHP site calling you - how would those guys be able to execute your .NET code??
So basically the design recommendation is: make sure your data contracts are just that - pure data, no behaviors, no methods, nothing like that.
If you need to do something on a piece of data - define a service method for it! That's what the whole service-oriented architecture is all about.
So basically: there's really no elegant or proper way to achieve what you want - except for making your methods into service methods that operate on simple data contracts.

Web services and interface compatibility

Adding a service reference to a web service (this is all WCF) in Visual Studio produces some generated code including a client-side restatement of the interface being exposed.
I understand why this interface is generated: you might be consuming a 3rd party service and not have access to the actual interface.
But I do, and the two are not assignment compatible even though the transparent proxy does indeed exactly implement the interface to which I want to cast.
I can use reflection, but that's ugly. Is there some way to defeat this faux type safety and inject metadata to so I can use an interface with a class?
My specific problem departs from the norm in complicated ways that have to do with a single client that uses some derivatives of a base class directly and uses others remotely via service references. The base class for each server needs to keep references to subscribing clients in a collection for enumeration to notify events, and the problem was type varied due to the use of proxies.
None of these answers solves my specific problem, yet every single answer was instructive and helpful. I found my own solution (use a dual binding) but I would never have figured it out if you hadn't radically improved my understanding of the whole business.
Three excellent answers. How to choose just one? I choose the first, because it directly solves the problem I first thought I had.
If you already have the contract dll at the client, you don't even need a service reference (unless you are using it to write the setup code for you) - you can simply subclass ClientBase and expose the Channel, and use that directly - something like (no IDE handy...):
public class WcfClient<T> : ClientBase<T> where T : class
{
public new T Channel {get {return base.Channel;}}
}
Then you can just do things like:
using(var client = new WcfClient<IFoo>())
{
client.Channel.Bar(); // defined by IFoo
}
You still need the configuration settings in the config to determine the address, binding, etc - but less messy than proxy generation. Also, you might choose to re-implement IDipsoable to deal with the fact that WCF proxies can throw in Dispose() (which is bad):
public class WcfClient<T> : ClientBase<T>, IDisposable where T : class
{
public new T Channel {get {return base.Channel;}}
void IDisposable.Dispose() {
try {
switch(State) {
case CommunicationState.Open: Close(); break;
// etc
}
} catch {} // swallow it down (perhaps log it first)
}
}
When you add the service reference, go to "Advanced" and make sure "Reuse types in referenced assemblies" is selected and that the assembly containing your interface definition is selected. You can also do this with an existing service reference by right clicking on it and going to "Configure".
In order to return an interface from a service you need to use the KnownType attribute:
http://weblogs.asp.net/avnerk/archive/2006/07/31/WCF-Serialization-part-1_3A00_-Interfaces_2C00_-Base-classes-and-the-NetDataContractFormatSerializer.aspx
If you want to return a custom type from the service:
http://msdn.microsoft.com/en-us/library/bb628653.aspx
Does any of that help?