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.
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 .NET WCF service (not a web service) with many methods, some accepting and returning complex data types. I use these services from my Windows Phone 7 apps. It all works great and it's easy.
Now I'm evaluating the feasibility of porting some of my apps to Android, but I can't figure out how to invoke my WCF services from an Android client.
I have a working example I found in Invoke webservices from Android.
But this looks to be accessing a "Web Service", not a WCF Service.
My service is at http://www.deanblakely.com/Service2.svc, and it contains a simple method named "SimpleTest" that just returns the string "Alive".
Using the code in the linked article, I put http://www.deanblakely.com/Service2.svc in SOAP_ADDRESS and SimpleTest in OPERATION_NAME. But I have no idea what to put in SOAP_ACTION and WSDL_TARGET_NAMESPACE. I don't even know if this approach is valid.
In .NET, Visual Studio builds us a "Service Reference" and everything just works.
I also don't understand the following two lines of code...
httpTransport.call(SOAP_ACTION, envelope);
Object response = envelope.getResponse();
With WCF services, the call is async so we make the call to SimpleTestAsync and leave a callback for the async return. These two lines of code appear to be synchronous, no?
When communicating with WCF services from a non-Windows client, you are basically treating it as an XML Web Service. If you configure your WCF service to use a basicHttp binding, it will act just like any other web service, as far as Java is concerned.
Normally, to call a WCF service from Java, you use wsimport to create a custom set of proxy and data classes, similar to the way a service reference works. Android doesn't have all the libraries needed for those classes, but I did find this URL:
http://code.google.com/p/androidclientgenerator-wsimport/
That is a proxy class generator specifically for Android. Instead of using the code on that web page, you may want to download this proxy generator; you simply have to pass it the URL to your service's WSDL page and it will create typed Java classes for everything. If you have complex types being passed back and forth, this is probably a much better option.
However, if you want to continue with the sample code, you'll need to fill in those variables you've identified. The variables are just the typical parameters for a SOAP envelope. These are defined in the WSDL for your service, and are primarily based on the namespace that you have defined for your service. (They are largely independent of the actual URL that your service lives at, with one exception). You specify the namespace in the WCF service contract:
[ServiceContract(Namespace = "http://namespaces.deanblakely.com/wcf")]
Note that the namespace URL doesn't need to point to a real resource, though frequently they do. It doesn't even need to be a URL (I often use urns); it just needs to be a unique string of characters. For now lets assume you assigned the above namespace to your service.
The WSDL_TARGET_NAMESPACE is just the namespace, exactly as above. The OPERATION_NAME is the name of the method you want to call, for example SimpleTest. The SOAP_ACTION is the combination of namespace an operation; in your case that would be http://namespaces.deanblakely.com/wcf/SimpleTest. In your WSDL you would see this described in an operation tag:
<wsdl:operation name="SimpleTest">
<soap:operation soapAction="http://namespaces.deanblakely.com/wcf/SimpleTest" style="document"/>
The SOAP_ADDRESS is the only one that actually points to your service file, e.g. http://www.deanblakely.com/Service2.svc.
Hopefully that will get you started calling in to your web service; if not feel free to stop back and get more assistance.
EDIT: Missed the part about async calls.
Yes, the method described on that web page is synchronous. WCF service methods are synchronous by default, with the option to include asynchronous calls when generating a service reference in Visual Studio. wsimport generates async-ready proxies, so using the Android client generate may also help you out in this area.
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 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
Greetings!
I am using a WCF library on an application server, which is referenced by an IIS server (which is therefore the client). I would like to put my validation in a place so that I can just call .Validate() which returns a string array of errors (field too short, missing, etc). The problem is, such functions don't cross the WCF boundary and I really don't want to code the same logic in the WCF service and in IIS/WCF client. Is there a way to use extension methods or something similar so both side can use use a .Validat() method which calls the same code?
Many thanks for any ideas!
Steve
If you control both sides of the wire, i.e. the server-side (service) and the client-side, then you could do the following:
put all your service and data contracts into a shared assembly
reference that "Contracts" assembly from both the server and the client
manually create the client proxy (by deriving from ClientBase<T> or by creating it from a ChannelFactory<T>) - do not use "Add Service Reference" or svcutil.exe!
put all validation logic into a shared assembly
reference that shared validation assembly from both projects
If you want to use a shared validation assembly, you must make sure the data types used on your server and client are identical - this can only be accomplished if you also share service and data contracts. Unfortunately, that requires manual creation of the client proxy (which is really not a big deal!).
If you'd use "Add Service Reference", then Visual Studio will inspect the service based on its metadata, and create a new set of client-side objects, which look the same in terms of their fields and all, but they're a separate, distinct type, and thus you wouldn't be able to use your shared validation on both the server-side and the client-side objects.
Do you have a problem with sending the data over to the server to be validated? In other words, your service interface actually offers the "Validate" method and takes a data contract full of data, validates it and returns a List where T is some kind of custom ValidationResult data contract that contains all the info you need about validation warnings/errors.
In a service architecture, you can't trust the client, who could theoretically be some other company altogether, to have done proper data validation for you. You always need to do it at the service layer and design for communication of those validation issues back to your client. So if you're doing that work at the server anyway, why not open that logic up to the clients so they can use it directly? Certainly the clients can (should) still do some kind of basic input validation such as checking for null values, empty strings, values out of range, etc, but core business logic checks should be shipped off to the service.