I am trying to write a running object table like WCF service (.NET 4.0) for providing access to some COM controls across processes. This service is accessed by both COM and .NET clients.
I chose WCF since it is recommended for inter-process communication and I also thought it would be good if I don't have to depend on ROT where I don't have much control over.
After solving several hiccups, I reached a road block. I don't know how to pass the COM control through the service and give it back to a client. The object never reaches the service. Though WCF is recommended for IPC, it does not provide out of the box support to pass COM objects. I also haven't found any solutions so far. May be WCF service is not the right approach to replace running object table. But I don't see a better way to do IPC.
Any suggestions on this?
A COM objref can't be passed around in a WCF message (well I guess you could create a MEOW interpreter on the receiver size and use CoMarshalInterThreadInterfaceInStream to pass the objref)
However, you could put the objects in the GIT and pass the GIT cookies around
But we can directly place COM object into the ROT by implementing IUNKNOWn interface
Related
Setting: I'm developing an intranet tool set for my department, the main point of which is to centrally manage data quality and accessibility, but also to automate and scale some partial-processes.
Problem: I currently have my business logic in a CLR assembly, which is available on my SQL-Server for other CLR assemblies that run automated ETL directly on the SQL-Server. I am also developing an intranet site, which also needs the code information in that business logic assembly, but referencing the CLR assembly code has been working out sub-optimally, in terms of deployment and code maintenance. Also another department has voiced interest in using the code-base and data for their own intranet site.
Question(s): I've read quite a few Q&A(1,2,3,4,...) on SO to this topic, but I find it a very encompassing, so I'll try to ask questions for a more specific case(i.e. a single BL and Data Access code base)
Is a WCF service the solution I want? All my potential service clients run on the same server, is there maybe another way to reference the same code base both in CLR assembly and website projects? I don't need support for different platforms(ex. Java) - everything is .NET(yay for in-house progr!) - is WCF overkill?
Can code from a WCF service be used like a class library, or do I need to program a new way for accessing classes/methods from the service?
Separation of Development, Test and Productive instances?
Can a WCF service be updated while clients are accessing it, or do I need to schedule maintenance windows? When I update the service, do I need to update the client as well in some way?
Can I dynamically set the service reference, like I currently am dynamically setting the database connection string, depending on if StageConfig = dev, test, or prod?
My CLR assemblies are written for .Net 3.5, but the websites for .NET 4.0, will that pose a problem?
What minimum set of .NET service architecture programming do I need to know to accomplish this? I'll learn more about WCF with time, but I need to evaluate architecting effort and weigh it against getting things done(feature requests). Does the MS tutorial get me the desired skill?
I appreciate answers to only single questions, if you feel you know something, I'll +1 whatever helps me get closer to a complete answer.
OK, so you want to make your code enterprise-wide. There are two fundamental problems to talk about when you want to do this, so I'll structure the answer that way:
You have to understand what WCF is all about.
You have to manage your dependencies correctly.
What WCF is about
WCF is a way of doing RPC/RMI (Remote procedure call/remote method invocation) which means that some client code can call code that is located somewhere else through the network.
A callable WCF service is determined by the ABC triplet:
The service specification is implemented as a .NET interface with a "ServiceContract" attribute. This is the Contract ("C")
The "location" of the service is determined by a pair : Address ("A") and Binding ("B"). The Binding determines the protocol suite to be used for communication between client and server (NetPipe, TCP, HTTP, ...). The Address is a URI following the scheme determined by the Binding ("net.pipe", "net.tcp", "http", ...)
When the client code calls a WCF service at a specific Address, with a specfic Binding, and a specific Contract (which must match what the server at the specific Address and the specific Binding is delivering), WCF generates a proxy object implementing the interface of the contract.
The program delivering the service is any .NET executable. It has to generate one or many WCF Hosts, that will register objects or classes that implement the service contract, and asociate each delivered service to a specific Address and Binding. (possibly many thereof)
The configuration can be through the app .config file, in which you will be specifying ABC triplets and assotiate these triplets with a name that you will use in your application. You can also do it programmatically, which is very easy.
WCF does not address your problem of deploying your application, or the configuration of addresses and binding. It just addresses the problem of letting two executables communicate with each other with strongly-typed objects (through a specific interface). Sharing the service configuration is up to you. You may use a shared .config file on a Windows share, or even set up a LDAP server that will deliver all the data you need to find your service (namely A and B).
Managing your dependencies correctly
In your scenario, there are three actors that want to use your WCF infrastructure:
Your SQLCLR assembly, which will be a client.
The intranet site, which will be another client.
The service host, which will be a server.
The bare minimum number of assemblies will be 4. One for each of the aforementioned actors, and one specifying the contract, which will be used by all three actors. It should contain the following things:
The interface specifying the contract.
All types needed by the interface, which will of course be sent through the network, and therefore must be serializable.
There should be nothing more in it, or else, it will be a maintenance nightmare.
Answer to your questions
I hope that my answer is clear. Let's sum up the answers to your questions.
Is a WCF service the solution I want? All my potential service clients
run on the same server, is there maybe another way to reference the
same code base both in CLR assembly and website projects? I don't need
support for different platforms(ex. Java) - everything is .NET(yay for
in-house progr!) - is WCF overkill?
Everything is overkill. WCF is rather easy to use and scales down very well.
Can code from a WCF service be used like a class library, or do I need
to program a new way for accessing classes/methods from the service?
Setting up a WCF on existing code requires only the implementation of an additional class, and some code creating the Hosts which will serve the aforementioned class.
Calling a WCF service requires the creation of a Channel, which is a .NET (proxy) object implementing the interface.
So basically, your business code remains in the same state.
Separation of Development, Test and Productive instances?
WCF does not take care of that. Different environments, different service addresses. You have to take care of this yourself.
Can a WCF service be updated while clients are accessing it, or do I need to schedule maintenance windows?
It depends on your maintenance policy. Kill the serving process and launch the new version is the basic upgrade mechanism.
When I update the service, do I need to update the client as well in some way?
Provided that you manage your dependencies correctly like I sketched in the previous section, you need to update the clients only if the service specification (the interface) changes.
Can I dynamically set the service reference, like I currently am dynamically setting the database connection string, depending on if StageConfig = dev, test, or prod?
You have to manage that, probably by etting Address and Binding for a service programmatically.
My CLR assemblies are written for .Net 3.5, but the websites for .NET 4.0, will that pose a problem?
Provided that you manage your dependencies correctly like I sketched in the previous section, the only constraint will be the minimum CLR version required by the "contract" assembly.
What minimum set of .NET service architecture programming do I need to know to accomplish this? I'll learn more about WCF with time, but I need to evaluate architecting effort and weigh it against getting things done(feature requests). Does the MS tutorial get me the desired skill?
You'll need the result of these exercises:
Make two executables, a client and a server, that will communicate
through a WCF contract located in a separate DLL. The configuration
should be located in the app .config file.
Make two executables, a client and a server, that will communicate
through a WCF contract
located in a separate DLL. The configuration should be determined programatically.
Try to send a serializable class as a parameter to your service.
Try to send a serializable class as a return value of your service.
After that, you'll need to think about the best/cheapest way to share the Addresses and Bindings of your services.
Hope it helps.
I have a WCF service which calls an STA Visual Basic 6.0 COM object. Everything works normally if only one client is using the service, but as soon as concurrent users start to call it, I'm in trouble and getting all kinds of random errors when calling one of the methods of the COM object.
At first I fixed this problem by adding support for the STAOperationBehavior attribute with the help of the article Calling an STA COM Object from a WCF Operation.
Well, it helped a lot and for some time everything seemed to work well, but now I started to get System.AccessViolationException errors on a particular server when more than one user is calling the service.
I've read that this is probably a thread problem, and I should use mutex or instancecontext in my web service.
What is the best practice for making sure that concurrent users can use an STA COM object in a WCF service without any problems?
If the object is not designed to be used simultaneously by multiple users, then you simply cannot allow multiple users to use it.
I have a WCF service application (actually, it uses WCF Web API preview 5) that intercepts each request and extracts several header values passed from the client. The idea is that the 'interceptor' will extract these values and setup a ClientContext object that is then globally available within the application for the duration of the request. The server is stateless, so the context is per-call.
My problem is that the application uses IoC (Unity) for dependency injection so there is no use of singleton's, etc. Any class that needs to use the context receives it via DI.
So, how do I 'dynamically' create a new context object for each request and make sure that it is used by the container for the duration of that request? I also need to be sure that it is completely thread-safe in that each request is truly using the correct instance.
UPDATE
So I realize as I look into the suggestions below that part of my problem is encapsulation. The idea is that the interface used for the context (IClientContext) contains only read-only properties so that the rest of the application code doesn't have the ability to make changes. (And in a team development environment, if the code allows it, someone will inevitably do it.)
As a result, in my message handler that intercepts the request, I can get an instance of the type implementing the interface from the container but I can't make use of it. I still want to only expose a read-only interface to all other code but need a way to set the property values. Any ideas?
I'm considering implementing two interfaces, one that provides read-only access and one that allows me to initialize the instance. Or casting the resolved object to a type that allows me to set the values. Unfortunately, this isn't fool-proof either but unless someone has a better idea, it might be the best I can do.
Read Andrew Oakley's Blog on WCF specific lifetime managers. He creates a UnityOperationContextLifetimeManager:
we came up with the idea to build a Unity lifetime manager tied to
WCF's OperationContext. That way, our container objects would live
only for the lifetime of the request...
Configure your context class with that lifetime manager and then just resolve it. It should give you an "operation singleton".
Sounds like you need a Unity LifetimeManager. See this SO question or this MSDN article.
I have been trying to get up to speed on Named Pipes this week. The task I am trying to solve with them is that I have an existing windows service that is acting as a device driver that funnels data from an external device into a database. Now I have to modify this service and add an optional user front end (on the same machine, using a form of IPC) that can monitor the data as it passes between the device and the DB as well as send some commands back to the service.
My initial ideas for the IPC were either named pipes or memory mapped files. So far I have been working through the named pipe idea using WCF Tutorial Basic Interprocess Communication . My idea is to set the Windows service up with an additional thread that implements the WCF NamedPipe Service and use that as a conduit to the internals of my driver.
I have the sample code working, however I can not get my head around 2 issues that I am hoping that someone here can help me with:
In the tutorial the ServiceHost is instantiated with a typeof(StringReverser) rather than by referencing a concrete class. Thus there seems to be no mechanism for the Server to interact with the service itself (between the host.Open() and host.Close() lines). Is it possible to create a link between and pass information between the server and the class that actually implements the service? If so, how?
If I run a single instance of the server and then run multiple instance of the clients, it seems that each client gets a separate instance of the service class. I tried adding some state information to the class implementing the service and it was only retained within the instance of the named pipe. This is possibly related to the first question, but is there anyway to force the named pipes to use the same instance of the class that is implementing the service?
Finally, any thoughts on MMF vs Named Pipes?
Edit - About the solution
As per Tomasr's answer the solution lies in using the correct constructor in order to supply a concrete singleton class that implements the service (ServiceHost Constructor (Object, Uri[])). What I did not appreciate at the time was his reference to ensuring the service class was thread safe. Naively just changing the constructor caused a crash in the server, and that ultimately lead me down the path of understanding InstanceContextMode from this blog entry Instancecontextmode And Concurrencymode. Setting the correct context nicely finished off the solution.
For (1) and (2) the answer is simple: You can ask WCF to use a singleton instance of your service to handle all requests. Mostly all you need to do is use the alternate ServiceHost constructor that takes an Object instance instead of a type.
Notice, however, that you'll be responsible for making your service class thread safe.
As for 3, it really depends a lot on what you need to do, your performance needs, how many clients you expect at the same time, the amount of data you'll be moving and for how long it needs to be available, etc.
Is it possible to configure a REST (WCF) service to run as STA instead of MTA?
This is approach is needed in order to run legacy COM objects. In order to configure ASMX web services to run as STA instead of MTA, there is a workaround available that uses an HTTPHandler to force the web service to run as STA.
An article by Jeff Prosise, http://msdn.microsoft.com/en-us/magazine/cc163544.aspx, details the workaround and how to apply it. Applying the same HTTPHandler to a REST-based WCF service (using Create New ADO.NET Data Service in Visual Studio) produces an error at the point at which the WebServiceHandlerFactory is called (it's being passed the HTTPContext, URL, etc.).
The handler works for ASMX web services, and I am able to add a WebMethod that returns the threading model as STA. However, even after setting ASPCompatibility (both in web.config and at the class level), the custom HTTPHandler always produces an error at the same point when trying to use a REST service. I've not configured any endpoints, since I am using a basic REST service with a couple of "service operator" methods. The error is:
Unable to cast object of type 'System.Web.Compilation.BuildResultCustomString'
to type 'System.Web.Compilation.BuildResultCompiledType'.
Read Integrating with COM+ Applications and see if that gets you anywhere.
I'm coming from the opposite direction (trying to convert my STA COM to MTA), and I believe it is automatic, if you instantiate the COM within your service instance and your COM is a proper STA with the proper registry entry. This is the way it worked for me, and I created at least 5 wrappers for this COM.
If you are creating threads manually, you may want to use SetApartmentState.