I am maintaining a legacy module where the system gets some information from the user (asp.net) and then calls a remote server via remoting to print a receipt on a printer connected to the remote server. Until recently, the remote server was able to connect to the database, so we passed only a int value (the paymentId).
But now, our main application (asp.net) is being moved offsite along with the database, but the receipt printing still has to work, so now, we are trying to send all the receipt's information so the server can generate the receipt from that instead of using the id and generating the receipt from the database. So, the concept is pretty basic, except... remoting is a bit of a pain sometimes. ;)
My object is serializable and inherits from MarshalByRefObject. It contains some int, decimal and string properties. The object goes through and seems to be serialized and deserialized correctly, but when any property is called, I receive the exception. I have read on other posts/forums that I must open a client channel on my client application (asp.net), but I'm confused.
My client application connects to many such remoting services depending on the printer it must print on. Must I create a client channel for each one? can I configure a client channel "on demand" when I connect to the server or must I create it at the app start? Can I specify when I connect (Activator.GetObject(...)) to use a bidirectional channel? Is there a way not to need the client channel (as in transform all properties to fields or something)?
Here is my stack trace (so we see the problem is the PaymentID property, which is the first one that is accessed) :
at System.Runtime.Remoting.Proxies.RemotingProxy.InternalInvoke(IMethodCallMessage reqMcmMsg, Boolean useDispatchMessage, Int32 callType)
at System.Runtime.Remoting.Proxies.RemotingProxy.Invoke(IMessage reqMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at GDCMLib.Reports.DataSources.PaymentReceiptItem.get_PaymentID()
at GDCMLib.Services.PaymentReceiptPrintRemoteObj.PaymentReceiptPrint.PrintPaymentReceipt(PaymentReceiptItem paymentReceipt) in u:\SVNClient\PortailDCM\trunk\Libraries\GDCMLib.Services.PaymentReceiptPrintRemoteObj\PaymentReceiptPrint.cs:ligne 37
Finally, as my data structure only used basic data types, I made sure it was transferred as a value type by changing it from a class to a struct. It now works perfectly.
Related
Introduction
We exchange income data with an external party. Each year income tax regulations change and a new message schema has to be implemented. Altogether we now have 8 different schema versions each of which are deployed in a separate 'year income tax' application and this amount increases by 1 each year.
Because we pay our hosting company per installed application, we want to decrease the amount of applications installed.
All these applications are functionally equal, which means we validate incoming messages, and forward valid messages into a specific MQSeries queue. Each invalid message is routed to a response queue. Each application has it's own 'valid' and 'invalid' message queues.
The plan
One generic application that processes all 8(+) messages. New schemas must be deployable without application changes or downtime for previous, running 'income year tax' flows.
So far...
I can receive multiple messages on the same BizTalk receive port (MessageType XmlDocument) and am able to validate these messages dynamically in an orchestration by calling a custom receive pipeline (XML Disassembler + XML Validator). Exceptions as well as valid messages are processed as prescribed. There are no references between the Schemas and the generic application, so schemas can be deployed without need to stop running processes. So far, so good.
The orchestration has 1 receive shape, and 2 send shapes (valid, invalid).
SSO contains the values for routing the 'valid' and 'invalid' messages to their correct queue. Based on the incoming messagetype SSO is questioned for the correct 'valid' or 'invalid' queuedefinition.
The problem
I have previously dealt with dynamic FTP, FILE, WCF and SMTP ports, which all worked flawlessly after supplying the adapter with the correct Context Properties. Even MSMQ seems to have a fairly straightforward approach on dynamically setting transport properties.
However, I cannot seem to find MQSeries MQMT ContextProperties to set the queuedefinition dynamically.
Microsoft does not provide much information on this, and extensive searches on the internet hasn't provided me with anything useful (examples) either.
I tried matching IBM's docs with Microsoft's, but altogether I am now stuck.
I would suggest to use MQSC adapter for IBM MQ integration. It is part of Host Integration Server MSI. It only requires MQ client to be installed on the server Vs MQ Server for Windows installation required by MQSeries adapter.
Set the OutboundTransportLocation property in following format mqsc://{channelName}/tcp/{server{({port})/{queuemanager}/{queuename}
TransportType = MQSC
Context Properties - Schema can be found within assembly MQSeriesEx.MQSPropertySchemaEx with namespace (http://schemas.microsoft.com/BizTalk/2003/mqs-properties).
There are only few context properties you would need to set if at all required.
Channel_HeartBeat
Channel_MaxMessageLength
Channel_UserId
Channel_Password
ConnectionTimeout
If additional properties are required than use MQSeries.MQSPropertySchema context properties.
Thanks Vikas for your suggestion.
I followed your directions and found it works!
However, I found it a little more complicated than needed as it required me configuring channel names for each flow.
The solution that best suited me was the one I had in mind all along, and it was right before me. My attempts failed because I made a fatal mistake by setting the outgoing message's properties where I should have set the dynamic send port's properties.
SendPort(Microsoft.XLANGs.BaseTypes.Address)="MQS://SERVER/QMANAGER/QUEUENAME";
I am building a c#/wpf project.
It's architecture is this:
A console application which will be on a virtual machine (or my home computer) that will be the server side.
A wpf application that will be the client app.
Now my problem is this - I want the server to be able to send changes to the clients. If for example I have a change for client ABC, I want the server to know how to call a service on the clients computer.
The problem is, that I don't know how the server will call the clients.
A small example in case I didn't explain it well:
The server is on computer 1, and there are two clients, on computers 2 and 3.
Client 2 has a Toyota car and client 3 has a BMW car.
The server on computer 1 wants to tell client 2 that it has a new car, an Avenger.
How do I keep track and call services on the clients?
I thought of saving their ip address (from calling ipconfig from the cmd) in the DB - but isn't that based on the WI-FI/network they are connected to?
Thanks for any help!
You could try implementing SignalR. It is a great library that uses web sockets to push data to clients.
Edit:
SignalR can help you solve your problem by allowing you to set up Hubs on your console app (server) that WPF application (clients) can connect to. When the clients start up you will register them with a specified Hub. When something changes on the server, you can push from the server Hub to the client. The client will receive the information from the server and allow you to handle it as you see fit.
Rough mockup of some code:
namepsace Server{}
public class YourHub : Hub {
public void SomeHubMethod(string userName) {
//clientMethodToCall is a method in the WPF application that
//will be called. Client needs to be registered to hub first.
Clients.User(userName).clientMethodToCall("This is a test.");
//One issue you may face is mapping client connections.
//There are a couple different ways/methodologies to do this.
//Just figure what will work best for you.
}
}
}
namespace Client{
public class HubService{
public IHubProxy CreateHubProxy(){
var hubConnection = new HubConnection("http://serverAddress:serverPort/");
IHubProxy yourHubProxy = hubConnection.CreateHubProxy("YourHub");
return yourHubProxy;
}
}
}
Then in your WPF window:
var hubService = new HubService();
var yourHubProxy = hubService.CreateHubProxy();
yourHubProxy.Start().Wait();
yourHubProxy.On("clientMethodToCall", () => DoSometingWithServerData());
You need to create some kind of subscription model for the clients to the server to handle a Publish-Subscribe channel (see http://www.enterpriseintegrationpatterns.com/patterns/messaging/PublishSubscribeChannel.html). The basic architecture is this:
Client sends a request to the messaging channel to register itself as a subscriber to a certain kind of message/event/etc.
Server sends messages to the channel to be delivered to subscribers to that message.
There are many ways to handle this. You could use some of the Azure services (like Event hub, or Topic) if you don't want to reinvent the wheel here. You could also have your server application track all of these things (updates to IP addresses, updates to subscription interest, making sure that messages don't get sent more than once; taking care of message durability [making sure messages get delivered even if the client is offline when the message gets created]).
In general, whatever solution you choose is plagued with a common problem - clients hide behind firewalls and have dynamic IP addresses. This makes it difficult (I've heard of technologies claiming to overcome this but haven't seen any in action) for a server to push to a client.
In reality, the client talks and the server listens and response. However, you can use this approach to simulate a push by;
1. polling (the client periodically asks for information)
2. long polling (the client asks for information and the server holds onto the request until information arrives or a timeout occurs)
3. sockets (the client requests server connection that is used for bi-directional communication for a period of time).
Knowing those terms, your next choice is to write your own or use a third-party service (azure, amazon, other) to deliver messages for you. I personally like long polling because it is easy to implement. In my application, I have the following setup.
A web API server on Azure with and endpoint that listens for message requests
A simple loop inside the server code that checks the database for new messages every 100ms.
A client that calls the API, handling the response.
As mentioned, there are many ways to do this. In your particular case, one way would be as follows.
Client A calls server API to listen for message
Server holds onto call, waiting for new message entry in database
Client B calls server API to post new message
Server saves message to database
Server instance from step 2 sees new message
Server returns message to Client A.
Also, the message doesn't have to be stored in a database - it just depends on your needs.
Sounds like you want to track users à la https://www.simple-talk.com/dotnet/asp.net/tracking-online-users-with-signalr/ , but in a desktop app in the sense of http://www.codeproject.com/Articles/804770/Implementing-SignalR-in-Desktop-Applications or damienbod.wordpress.com/2013/11/20/signalr-a-complete-wpf-client-using-mvvm/ .
I have two queries here :-
1) What is the basic difference between Microsoft.ServiceModel.Web.RequestInterceptor and System.ServiceModel.Dispatcher.DispatchRuntime.MessageInspectors (IdispatchMessageInterceptor)
Both appears to be Request/Message interceptors which can be used to implement custom validation/interceptors in the request pipeline.
When to use one on another?
2) Also how to plugin RequestInterceptor in RouteTable.Routes.Add(new ServiceRoute())
I have class like this -
public class AuthenticationInterceptor : RequestInterceptor
{
//Authentication logic goes here......
}
and a route definition like this : -
RouteTable.Routes.Add(new ServiceRoute(routePrefix, new MyServiceHostFactory(container, (sh) => {
foreach (System.ServiceModel.Dispatcher.ChannelDispatcher cd in sh.ChannelDispatchers)
{
foreach (System.ServiceModel.Dispatcher.EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.MessageInspectors.Add(new AuthenticationInterceptor());
}
}
return sh; })));
Here is the definition of MyServiceHostFactory: -
public MyServiceHostFactory(IocContainer container, Func<ServiceHost, ServiceHost> createservicehost = null);
Now it is throwing following error : -
The best overloaded method match for 'System.Collections.Generic.SynchronizedCollection<System.ServiceModel.Dispatcher.IDispatchMessageInspector>.Add(System.ServiceModel.Dispatcher.IDispatchMessageInspector)' has some invalid arguments
at this line : -
ed.DispatchRuntime.MessageInspectors.Add(new AuthenticationInterceptor());
I know why, it is just because I am trying to hookup RequestInterceptor in MessageInspector. Both comes in different interface hierarchy.
So what should I do here?
Edit:
Also note, I cannot change AuthenticationInterceptor logic as the code in not under my control.
Here are the answers to your questions(you need to read through point number 2 to understand Interceptors and Inspectors a little):
1. Solution to the Error (you need to add your code logic to it )
Implement IDispatchMessageInspector in the following code. Please note that the name of the following class should change to inspector, but as you have mentioned you cannot change it so you should implement the interface here. Otherwise, it is recommended to create another class with Matching Inspector suffix and implementation.
public class AuthenticationInterceptor : RequestInterceptor, IDispatchMessageInspector
{
//Authentication logic goes here......
object IDispatchMessageInspector.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
//Your code here.
}
void IDispatchMessageInspector.BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//Your code here.
}
}
2. Difference between RequestInterceptor and MessageInspectors
In any client server communication there can be two important phases of communication. First, when a client establishes connection with the server and second when they both communicate.
When establishing the connection it is not necessary that the client which is trying to establish the connection is a valid client. It could be an unauthorized request as well or it could be possible that the request is valid but not intended to the destined server and requires authorization or connection rerouting.
A good example of rerouting is when :
you want regional client/servers to avoid cross region communications but one of the client(which is valid) but tries to connect to a different region server.
You want the servers selectively decide if you wish to allow cross region client-server communications for a few exceptional users.
There could be even more complex rerouting scenarios which is out of scope of this answer.
So in WCF, the Rest starter kit provides you additional ability to intercept the request during connection establishment phase. The interceptor (in your case the AuthenticationInterceptor) should authenticate such requests and if the request is invalid, it can log the necessary entries and just reject to process any communication further from this rejected client/session.
We have many benefits of having a RequestInterceptor:
It helps us to validate the incoming request at a very early phase.
It can help us to build custom authenticators or rerouting components.
It blocks any further message processing during request phase itself which is very important to keep the unnecessary load away from the WCF Service/Server.
Message Inspectors:
The MessageInspectors can be treated as part of second phase of client-server communication when a Request is validated and connection is well established and thus it's the time when client-server has to started communicating by passing messages to each other. Now, in your application environment it could be possible that the messages pass using a binary, xml or json serialized format. There could be applicable encryptions.
An example is, it is possible that a message arrives from client A and given to Server B now server Queues it up to another Server C which can wait for some more information from Another Server D. Once Server D provides the information, the Server C which has the message in queue further joins the raw message received from Server B and Server D, gives it to another service to deserialize and convert it to something meaningful which can be returned to server B and B returns it back to Client A.
Quite complex, right? But a multi server authentication like payments by credit card using mobile PIN somewhat works in similar manner, though could be not exactly the same, but even more complex.
In WCF, Interceptors and Inspectors can work together and their duties are different. An interceptor validates the end user/connection/rerouting and an Inspector validates/processes the message.
A few points:
You can build your own message inspectors by implementing IClientMessageInspector for the client side and IDispatchMessageInspector on the server side.
You can implement both of the interfaces in a single class if you are owner of both client and server components.
Here, in your case it seems you need to implement IDispatchMessageInspector.
A class implementing IDispatchMessageInspector does not intercepts as I mentioned before but is meant to 'Inspect' an incoming message and any outgoing message and this Inspector can be hooked using configurations when a message arrives from the client.
Please note that by this time at Inspector levels, any message which arrives is already processed at various channel stack levels and assigned to which WCF Service will process this request. If you are using any encryption in between, then the message has already been decrypted. But, the message is not deserialized yet.
A use of having your custom Inspector is it could be possible that your system implements custom serialization format like (SWIFT/FIX protocol in banking) or another level of zip/unzip encoding etc.
This custom inspector can deserialized the data and give it to your component COMP which is actually meant to work on the deserialized data.
An IDispatchMessageInspector interface has got two methods which you need to implement:
a) AfterReceiveRequest and
b) BeforeSendReply(ref Message, Object).
AfterReceiveRequest is the method which can dezerialize the data and gives it to COMP, and BeforeSendReply is the method which again serializes the data and perform any operation on the message.
You can use behaviors to attach the MessageInspectors for every message your web service receives.
Both, custom Interceptors and Inspectors are largely meant to be used in Enterprise Platform or a Highly customizable platforms.
Hope this answer helps you. You can read more on the following links (possible you have gone through the first one):
http://msdn.microsoft.com/en-us/library/ee391967.aspx
http://msdn.microsoft.com/en-us/library/aa717047(v=vs.110).aspx
Regards
Kajal
I have a client that serializes a class to a stream, which goes through a socket, to my server.
So i send this object to my server, where my server would save the ''object'' by doing:
object readObject = formatter.Deserialize(stream);
It fails to deserialize saying:
Unable to find assembly etc. etc.
Does this mean there is no way for my server to take the object, push it through a few more sockets to other clients, where the clients deserialize it? Does the server really require the original class in order to deserialize to an object?
I do not want my server to be able to open all these objects at all, i just want it to serve was a broadcaster to all my active clients.
Help is appreciated,
Smiley
Assuming that you have the source code to the client and server, you could extract the class definition for the object into a separate class library project (DLL) and then reference it from both the client application and the server application. That way, both of them have knowledge of the class and deserialization should work fine.
For example code look at TCPMessageServer available open source from codeplex
https://tcpmessageserver.codeplex.com/
All the examples i found are sending only text/string data over the network. I figure out how to send different types of objects (ArrayLists etc).
I'm now trying to find out how to process commands sent from the client on the server.
From the client i have to :
add ä "Student" in the database
delete a student in the database
get all students in the database etc.
so, if i create a protocol on the client side with a method "processCommand" sometimes i have a different number of parameters, depending on the request from the client ( when adding a student, i have to send the student object) , ( when getting data from the database i don't have to send any parameters) ; also i have to return different type of objects.
How can i do this ?
Thank you very much.
As suggested by #marc_s. There is no reason to reinvent the wheel. Use WCF with tcpBinding.
If you need to do it by yourself you need to use some kind of serialization. You also need to attach a header since TCP is stream based and do not guarantee that everything arrives in the same Receive.
I would do it like this:
Serialize your object into a byte buffer using BinaryFormatter.
Send a header containing version (an int) and number of bytes in the byte buffer (int)
Send the byte buffer.