Exposing a WCF Service as a COM+ Component - wcf

I am working with a client that has multiple Classic ASP websites, but would like to use AppFabric Caching within these sites to help lighten the load they currently have on their database.
The first approach we used was creating a .NET wrapper for the AppFabric API and exposing it to the ASP websites as a COM object. This method worked, but they soon began to experience high memory usage that crashed their webserver. The COM component is hosted within the application scope of the site so that could be a big part of the issue.
One of the options I came up with was creating a WCF Service and exposing it to the ASP sites as a COM+ Service. Unfortunately, my exposure to COM+ at this point is limited. My reasoning behind this is the service can be utilized from the ASP websites, but hosted out of process from the websites. This would also allow me to performance test the COM+ service independently from the websites.
I am having trouble coming up with start to finish documentation for creating and publishing the COM+ service. The MSDN documentation I’ve read appears to skip significant steps in the process.
As an example service I have the following:
namespace TestComService
{
[ServiceContract(SessionMode = SessionMode.Allowed, Namespace = "http://tempure.org/DD1F6C46-1A25-49CC-AA20-2D31A3D0C0AA", Name = "IService")]
public interface IServiceContract
{
[OperationContract]
string Get(string key);
[OperationContract]
void Set(string key, string value);
}
public class Service : IServiceContract
{
private readonly Dictionary<string, string> cache = new Dictionary<string, string>();
public string Get(string key)
{
return cache[key];
}
public void Set(string key, string value)
{
cache.Add(key, value);
}
}
}
The configuration is as follows:
<system.serviceModel>
<bindings>
<netNamedPipeBinding>
<binding name="comNonTransactionalBinding"/>
</netNamedPipeBinding>
</bindings>
<comContracts>
<comContract contract="{DD1F6C46-1A25-49CC-AA20-2D31A3D0C0AA}" name="IService" namespace="http://tempure.org/DD1F6C46-1A25-49CC-AA20-2D31A3D0C0AA" requiresSession="true">
<exposedMethods>
<add exposedMethod="Get"/>
<add exposedMethod="Set"/>
</exposedMethods>
</comContract>
</comContracts>
<services>
<service name="{3957AA9E-4671-4EF0-859B-1E94F9B21BEE},{5D180F85-65D8-4C0C-B5D6-9D28C59E29AE}">
<endpoint address="IService" binding="netNamedPipeBinding" bindingConfiguration="comNonTransactionalBinding" contract="{DD1F6C46-1A25-49CC-AA20-2D31A3D0C0AA}"/>
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/TestComService"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
I’m still a bit confused as far as hosting goes. Can this be hosted within IIS, or to I need to create a separate service to host within that?
Once again, I'm open to any suggestions or input someone with more experience with the matter can provide.

We use COM+ called directly from a web service and WCF Service. I do not believe you need to use a WCF wrapper, called from your ASP.NET application, to use the COM+ component unless it will run on a different server.
You need to install the COM+ component separately from the Web App on the server. It must be registered in the GAC. You create a reference to the COM+ object/DLL file in your ASP.NET application. When you call the DLL file it uses the deployed object registered in the GAC which calls the registered COM+ object.
We had some problems with the native .NET installer. It does not always register the COM+ component correctly. So I wrote a simple batch file that does the job. Here is batch code. I deploy regsvsc.exe with the application so it always knows where to find it.
regsvcs /fc MYCOM+.DLL

Related

Reliable Messaging accessible after adding ASMX web service via Service Reference

In VS2013 I have added Service Reference, not Web Reference, to existing legacy ASMX web service(s).
Does this somehow give this reference the ability to implement WCF features like Reliable Messaging, or any other new features of WCF?
I have done some reading and I think that at least for Reliable Messaging we do not magically get this ability, since as I understand it this feature has to be both enabled on the 'client' and 'server' side, ie both endpoints, and of course the old ASMX web services, the server in this case, don't support Reliable Messaging standard, even if I were to somehow configure the 'client' to do so.
I have been told by resident developers to add these old ASMX web services as a Service Reference as it gives the ability to do async calls and 'some' other configuration benefits, but I am not too sure about this from what I have now read.
What you need is an adapter pattern. The way I am looking at it is more from design patterns perspective rather than WCF.
[ServiceContract]
public interface IService
{
[OperationContract]
string SayHello(string toWhom);
}
public class Service : IService
{
public string SayHello(string toWhom)
{
// consume the ASMX service here and return the result.
}
}
in the binding you can use the features that are missing in ASMX.
<bindings>
<wsHttpBinding>
<binding>
<reliableSession/>
<security>
<message />
</security>
</binding>
</wsHttpBinding>
</bindings>

What is the best way to dynamically host multiple WCF services in a single Windows service sharing a mex endpoint?

I have been given a request to dynamically host multiple WCF services in a single Windows service.
The requirements are the following:
The services are singletone instances implementing some service contract interfaces.
The services aren't known at compile-time - at runtime a collecion of unknown singletone services are passed to the application.
All services are exposed via the same mex endpoint
The endpoints are set programmatically (without using app.config)
I tried solving the problem from two different approaches:
The first approach is to create and open a ServiceHost for each service instance. The problem with this approach is that each ServiceHost is exposed via its own mex endpoint.
The second approach is to create a single ServiceHost for all services, and expose them all via the same mex endpoint.
I tried a couple of ways to implement the second approach:
The first way is to create a service type in runtime (using CodeDom or Reflection.Emit) that wraps all instances, and implements all of the service contracts and routes a given method call to the suitable service instance. This works but seems like a overkill. (I rather to not generate code if possible)
The second way is to programmatically setup ServiceEndpoints for requested contracts. I modified this following code example so it will route a method call to the corresponding service instance's method. The problem with this solution is that a hack is made in order to associate a ServiceEndpoint to its ChannelDispatcher.
Am I missing other approaches? Is there anyway to overcome the problems I mentioned?
If I'm understanding your problem correctly, then one approach would be to implement multiple contract interfaces in a single service class. By doing that, you should be able to get the metadata from a single mex endpoint. Here's a very simple example:
[ServiceContract]
public interface IServiceContract1
{
[OperationContract]
bool DoStuff1();
}
[ServiceContract]
public interface IServiceContract2
{
[OperationContract]
bool DoStuff2();
}
public class ServiceContractImplementation: IServiceContract1, IServiceContract2
{
bool DoStuff1()
{
return true;
}
bool DoStuff2()
{
return true;
}
}
Then in the web.config (or in code in your case):
<service name="ServiceImplementation">
<endpoint binding="basicHttpBinding" contract="IServiceContract1"/>
<endpoint binding="basicHttpBinding" contract="IServiceContract2"/>
<endpoint address="mex" contract="IMetadataExchange" />
</service>

How to set up RIA services with Silverlight 4.0 and without EF

As a Silverlight newbie, I am finding it really hard to set up an RIA Web service. The examples available on the web almost always refer to Entity framework as the ORM but we are using NHibernate as our ORM. I am aware of the tutorial by Brad Abrams where he uses NHibernate as the ORM but most of it goes above my head because I am also a newbie at NHibernate and some of the concepts of RIA are not clear to me e.g. DomainService.
I'd like to first keep it simple and ignore the ORM at the moment. So, can anyone point me in the right direction as to how to get a "vanilla" web service going with Silverlight 4.0 and the latest release of RIA? For instance, how would I expose a method which returns the integer 100 and then call the method from my SilverLight application? Also, I am not sure if it's relevant or not but the Silverlight application is hosted in ASP.NET MVC 2.
To me it should be so simple but I'm really struggling with it at the moment.
TIA,
David
These scenarios (non-EntityFramework RIA Services with Silverlight) are definitely under documented and I hope to post some blog entries soon to cover these scenarios (including how to use NHibernate).
Here is one way to do what you are asking:
Install "Silverlight 4 Tools for Visual Studio 2010" if you haven't already:
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=b3deb194-ca86-4fb6-a716-b67c2604a139&displaylang=en
Create a new Silverlight Navigation Application in Visual Studio 2010 (check the box to enable RIA Services).
Modify the web.config in the web project in the following ways:
In the <system.web> section, add:
<httpModules>
<add name="DomainServiceModule"
type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule,
System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</httpModules>
Add a <system.serviceModel> section as a peer of <system.web>:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Add the following references to the web project:
System.ServiceModel.DomainServices.Hosting
System.ServiceModel.DomainServices.Server
Create a new class VanillaDomainService in the web project that contains your "return 100" method:
[System.ServiceModel.DomainServices.Hosting.EnableClientAccess()]
public class VanillaDomainService :
System.ServiceModel.DomainServices.Server.DomainService
{
public int ReturnInteger100()
{
return 100;
}
}
Now back to the Silverlight Application project, in Home.xaml.cs, in the OnNavigatedTo method, call your new RIA Services method (remember all calls are async):
protected override void OnNavigatedTo(NavigationEventArgs e)
{
SilverlightApplication1.Web.VanillaDomainContext oneVanillaDomainContext =
new SilverlightApplication1.Web.VanillaDomainContext();
oneVanillaDomainContext.ReturnInteger100(
anInt => MessageBox.Show(anInt.Value.ToString()), null);
}
Now build and run and that should be it.
I tested this code and it worked for me.

WCF Service in ASP.NET application generating intermittent 404 errors

This problem has defeated my attempts at Google, so here goes. We were having an issue getting data from a WCF service (just lookup data, so we enabled it for HTTP GET requests). Every once in while it will return a 404. The stack trace does NOT appear to have WCF in the mix - the StaticFileHandler appears to be attempting to serve it.
I created a a sample WCF service on ASP.NET 3.5 SP1 and am able to reproduce the problem. This is my sample service - the only differences from stock WCF at this point are the AspNetCompatibilityRequirements and the enabling of WebScript and HTTP GET:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
public string DoWork(string param1)
{
System.Threading.Thread.Sleep(150);
return "bar";
}
}
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet]
string DoWork(string param1);
}
Service config:
<service name="namespace.Service1">
<endpoint
behaviorConfiguration="WebScriptEnabled"
address="http://localhost:2961/svc/Service1.svc"
binding="webHttpBinding"
contract="namespace.IService1">
</endpoint>
</service>
Behavior config:
<behaviors>
<endpointBehaviors>
<behavior name="WebScriptEnabled">
<enableWebScript />
</behavior>
</endpointBehaviors>
</behaviors>
My node has aspNetCompatibilityEnabled="true">, but otherwise everything is pretty much OOB. I have no customizations on webHttpBinding at all.
If I F5 on VS 2008 using the built in web server and hit the URL, the very first request will result in a 404. If I continue to hit it with even a light load (7-10 simultaneous requests), I'll get a handful of 404 errors.
If I then let the load drop down to nothing and rerun my test, I can go to 50 simultaneous requests easily WITHOUT any errors.
My real service is much more complicated than this, but the fact that I can get a (nearly) stock sample to show this behavior is concerning, as though there might be a framework related issue. I've enabled WCF diagnostics and tracing but nothing shows in the logs (not unexpected since WCF is not in the stack trace when the 404 occurs).
I hope I'm doing something wrong and have not discovered a framework bug. My production environment is IIS6 and appears to exhibit the same behavior as my development server.

How to get working path of a wcf application?

I want to get the working folder of a WCF application. How can I get it?
If I try
HttpContext.Current.Request.MapPath(HttpContext.Current.Request.ApplicationPath)
I get a null reference exception (the Http.Current object is null).
What I meant with the working folder was the folder where my WCF service is running. If I set aspNetCompatibilityEnabled="true", I get this error:
The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
I needed the same information for my IIS6 hosted WCF application and I found that this worked for me:
string apPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
As always, YMMV.
Please see ongle's answer below. It is much better than this one.
Updated after more information
The following worked for me. I tested it with a new WCF Service I hosted on IIS through a Service1.svc.
Add <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> to web config. <system.serviceModel>..</ ..> existed already.
Add AspNetCompatibilityRequirementsAttribute to the service with Mode Allowed.
Use HttpContext.Current.Server.MapPath("."); to get the root directory.
Below is the full code for the service class. I made no changes in the IService1 interface.
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
public void DoWork()
{
HttpContext.Current.Server.MapPath(".");
}
}
And below is an excerpt from the web.config.
<system.serviceModel>
<!-- Added only the one line below -->
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<!-- Everything else was left intact -->
<behaviors>
<!-- ... -->
</behaviors>
<services>
<!-- ... -->
</services>
</system.serviceModel>
Old answer
What do you mean by the Working Folder? WCF services can be hosted in several different ways and with different endpoints so working folder is slightly ambiguous.
You can retrieve the normal "Working folder" with a call to Directory.GetCurrentDirectory().
HttpContext is an ASP.Net object. Even if WCF can be hosted on IIS, it's still not ASP.Net and for that reason most of the ASP.Net techniques do not work by default. OperationContext is the WCF's equivalent of HttpContext. The OperationContext contains information on the incoming request, outgoing response among other things.
Though the easiest way might be to run the service in ASP.Net compatibility mode by toggling it in the web.config. This should give you access to the ASP.Net HttpContext. It will limit you to the *HttpBindings and IIS hosting though. To toggle the compatibility mode, add the following to the web.config.
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
Depending on what you want. I usually want to resolve a url like "~/folder/file". This is what worked.
System.Web.Hosting.HostingEnvironment.MapPath("~/folder/file");
More general, I am using this one
AppDomain.CurrentDomain.BaseDirectory
The aspNetCompatibilityEnabled="true" should have resolved my problem, but I got this error:
The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
I resolved my problem with getting the physical path of my running WCF service by getting it from my current app domain:
AppDomain.CurrentDomain.BaseDirectory
In order to reference ASP.NET features like the HttpContext object, you need to run your WCF app in ASP.NET compatibility mode. This article explains how to do this.
Use HostingEnvironment.ApplicationPhysicalPath in WCF to find your application physical path.
Use namespace
using System.Web.Hosting;