Sending Castle Proxy from NHibernate with MassTransit over MSMQ causes StackOverflowException - c#

I'm trying to send a message with MassTransit over MSMQ. The message contains two properties which are types obtained from an NHibernate query and contain Castle Proxies (for lazy loading).
If I send the message (using bus.Endpoint.Send(msg)) with the proxies as part of the message I generate a StackOverflowException. If I don't assign these two properties, and leave them null, the message fires through the queue without issue.
Is this just the way it is, or am I doing something wrong with the MSMQ/MassTransit setup?
If not, would I need to use something like AutoMapper to get rid of these proxies?

This is likely an exception based upon the dynamic proxies generated and the serializer being used. I assume it's the default XML serializer? I would post an issue to the github page for MT so we can look at this: https://github.com/MassTransit/MassTransit
These messages should be consider contracts for decoupling between processes. Using NHibernate entities, these services become coupled with more than just the messages as a DB change could effect the other consumers. Ideally you would always map this to another object before passing it along.
Is there a reason why you aren't just bus.Publish(msg) instead of sending directly to the Bus' endpoint? You could join the MT mailing list and discuss this in more detail: http://groups.google.com/group/masstransit-discuss
I hope this helps!

Related

Configuring Outbound WCF message body with promoted context properties

I have a send port that receives a document with a set of promoted context properties. The adapter on the send port is set as WCF-SQL, and have been configured to connect to the SQL server.
The only part missing is configuring the messages tab, so that the correct message is being sent to the database. Right now I simply have some hardcoded values along with the message itself:
<bizSaveDocument xmlns="http://schemas.microsoft.com/Sql/2008/05/Procedures/dbo">
<conversationID>547e0702-c0c8-4535-9ab0-fa52b2fdbdd0</conversationID>
<dataType>OIO</dataType>
<fromID></fromID>
<toID></toID>
<msgInfoExtension><![CDATA[<infoExt><fileInfo fileName="ublinvoice.xml" encoding="utf-8" /></infoExt>]]></msgInfoExtension>
<msgBody><bts-msg-body xmlns="http://www.microsoft.com/schemas/bts2007" encoding="string"/></msgBody>
<msgBodyBin></msgBodyBin>
</bizSaveDocument>
I'm unsure how to properly insert my promoted context properties into these elements. To give an idea of where I want to configure this XML, see the screenshow below:

I cannot use the body option, since I need to insert some promoted properties into the database. Looking at the MSDN there seems to be no explanation of how to accomplish this. See this link: https://learn.microsoft.com/en-us/biztalk/core/specifying-the-message-body-for-the-wcf-adapters
For the receiving message, I created a pipeline component which promoted the required properties and works fine.
Is this simply not possible in standard Biztalk? If not, I will need to create an additional pipeline component to handle the sending.
Ah, ok, I see what you're doing....so....don't do it this way.
The best and essentially correct way to handle this is with a normal BizTalk flow with Maps and an Orchestration. Remember, there is nothing wrong with using an Orchestration, if someone is telling you to not use Orchestrations, they are, well, wrong.*
Basically, Map to you SQL Schema using temp values, then set them from the Context using Distinguished fields.
Don't ever bother with the Messages Tab, it's basically hiding code where it should never be.
If they still make you do it some other way, you need to tell your management that this will take you about twice as long to implement because you have to create a anti-pattern that replicates built in functionality.

Operation Contract Serialization Error With Entity Framework 6.0 and WCF

In my C# app I am trying to send a request through an intermediary DLL to add data to QuickBooks. The intermediary DLL, based off of a setting, sends the item add request through a WCF service. The service project is using Operation Contracts for all methods housed within it. It does not have any data contract/data members.
This works find for invoices and other transactions. However, when adding an item, I receive this error:
A first chance exception of type
'System.Runtime.Serialization.SerializationException' occurred in
System.Runtime.Serialization.dll
Additional information: Type
'System.Data.Entity.DynamicProxies.QBLookUp_A96F53AD8DA6F21651FEF0B25078616AB4989DA745EE06E345D365196574CE0F'
with data contract name
'QBLookUp_A96F53AD8DA6F21651FEF0B25078616AB4989DA745EE06E345D365196574CE0F:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies'
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.
Looking around here on Stack Overflow, I ran into several threads that suggested to turn off proxy creation in my EF Model to get around this issue. So I inserted this bit of code into the constructor in my EF project:
this.Configuration.ProxyCreationEnabled = false;
However, when I turn off proxy creation, I run into two new problems:
A) Various bits of data do not show up in my C# app. This data is supplied to the app by Entity Framework.
B) I receive this error when trying to save the item via the WCF service:
Additional information: Object graph for type 'System.Collections.Generic.HashSet`1[[EFModel.Item, EFModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' contains cycles and cannot be serialized if reference tracking is disabled
This leads me to the following conclusion - I need to have proxy creation enabled in order for my application to work, and at the same time I may be doing something wrong with my service. Does anyone have any suggestions as to what I could change to get things working?
This problem generally comes when you try to serialize data which cannot be done by WCF. Why the first answer works fine for some casea because if you will turn off the proxy creation WCF will know which data need to be serialized if you mark your class with DataContract attribute if proxy would be on then proxy classes will be created on FLY and WCF can not serialize those classes.
IF you are using entity framework so I guess you would have been using lambda expression to retrieve those records from db in your client. Since WCF does not serialize lambda Expression by default so you can not pass lambda expression to querying those records from client.(Why - since WCF is used for SOA architecture and service is generic so that any kind of client(JAVA,C++ etc) can consume this service and lambda expression is specific to some language. If it will implement this feature in WCF then it will violate the rule of SOA architecture).
If you still want to use lambda expression then you need to create dynamic lambda expression. But that is not better way to implement because client will be bound to use in that way. Try not to use lambda expression in client.
creating Dynamic Lambda expression is given in this link:
https://www.codeproject.com/Articles/1079028/Build-Lambda-Expressions-Dynamically
In the end I resorted to using a DTO for all of the objects that EF was creating proxies for that which WCF could not handle. It was a bit of extra code but the results worked out nicely, as I am still able to use proxies and lazy loading.

How to encapsulate code for WCF services without using a base class?

All of our services take a ServiceCallContext object as a parameter. The service then creates a broker and tells the broker what connection string to use based on the ServiceCallContext.
In other words, some of our customers have their own databases so the service calls have to point the brokers to their databases.
I would like to take the code that looks at the ServiceCallContext and chooses the correct connection and put it in a base service class. My team lead doesn't like that idea because with services he feels that this would be 'hiding' behavior and that this would be a bad thing. He suggested that there may be better ways to accomplish the same thing through some sort of WCF extensions.
I honestly don't care how we implement the code so long as I can reuse it because I think it's absolutely silly for me to be rewriting it in every service I create. I began looking into some WCF videos on PluralSight and it looks like there's a lot of great stuff it can do but unfortunately I'm not quite sure where to start. Can anyone give me a little direction as to whether WCF can accomplish what I'm trying to do and if so what particular features of WCF am I looking for?
The functionality you need is a custom interceptor.
This allows you to tell the WCF stack to look at incoming messages and the do some action based on them. If you wrap the interceptor up into it's own assembly then you can reference it from multiple services.

C# object metadata

Is there any way to glue metadata to an object in C#?
Context: Framework which is sending messages between peers over the network. Messages can be arbitrary serializable user-defined .NET types.
Of course, when a message is sent by a peer, the framework could wrap the object into a Message class which saves the metadata, and the receiver could unwrap it. However, the processing method of the peer could decide to resend the message to another peer - however, I want to keep the original metadata. The user should not be required to use Message.RealMessage all the time except when resending it.
I thought about keeping the wrapped instance in a dictionary and upon resending looking up if there is already a wrapped instance in the dictionary and resending that one, however, as messages may not be resent at all (or resent multiple times) this would require more and more memory.
Any solutions? Maybe C# directly supports gluing additional information to an object? Normally I would go for an internal interface, however, the user would have to derive all its classes from a framework's base class, which is not possible.
Edit: I kind of want to say "here is an object of WrappedMessage but you are only allowed to use the interface provided by the class T".
There is the ConditionalWeakTable that should do what you want a little better than using directly a Dictionary.
To quote:
Enables compilers to dynamically attach object fields to managed objects.
You can ignore the part about the class being for compiler :-)

WCF - Complex Objects - KnownTypes

Ok, not really sure how to word, but will try my best.
I have a number of WCF services that are setup and run awaiting an object to come in for processing.
WCFServiceA
WCFServiceB
WCFServiceC
Service A will run some processing and decide to send the object onto Service B or C.
So my object has [DataContract] attribute on all classes in it and [DataMember] on all properties.
So so far so good.
But now I well lose all the functionality from my object, as this is now basically a serialised version of the object.
So is it best practice if I want to use a full complex object to include the same assembly in all 3 services as a reference and send things across as "KnownTypes"?? Providing the basic DataContract and DataMember for anything using the services that does not know these types so they can still create these object for the services to run with?
Hope I have worded this correctly and you understand my question here.
:EDIT:
To try and clarify.
The object I am sending can have a "Policy" attached to it, this policy object is a class and can be one of several types, vehicle, house, life, pet policy etc.
But the actual type will not be known by the receiving service. Hence the need for KnownTypes.
I think I just answered my own question!! :)
That was a good explanation of the problem. The draw back I see in this approach is if you are going to update the object , say adding new properties or removing some , all the 3 service needs to be updated with the new assembly.
Using of the known types can sometimes lead to backward compatibility issues when you want to upgrade the objects in live depending on the setup.
Or create a DTO (Data transfer object) with just the properties and pass it across the services as a data contract and strip the complex logic in to a helper class which can be referenced by the services.

Categories