I have a long-running service that gets data from one source, manipulates it, stores it in a database, etc.
I'd like to expose some methods on that service to other applications. Currently we do this via .NET Remoting but I'd like to move to WCF.
Unfortunately, I the endpoint I connect to is never the one I exposed via my long-running service. Below is a simple example:
[ServiceContract]
public interface ITestWcfService
{
[OperationContract]
CounterResult GetCurrentValue();
}
public class TestWcfService : ITestWcfService
{
private ITestWindowsService _service;
public TestWcfService() { /*NOTE: For discoverability*/ }
public TestWcfService(ITestWindowsService service)
{
_service = service;
}
public CounterResult GetCurrentValue()
{
return _service.GetCurrentValue();
}
}
public interface ITestWindowsService
{
CounterResult GetCurrentValue();
}
Then I have my actual Windows Service, which self-hosts the WCF service via the ServiceHost class.
public partial class TestWindowsService : ServiceBase, ITestWindowsService
{
private static ServiceHost _wcfService;
public TestWindowsService()
{
InitializeComponent();
}
public void OnStart(string[] args)
{
//Create instance of WCF, passing in reference to this service instance
TestWcfService wcf = new TestWcfService(this);
_wcfService = new ServiceHost(wcf);
}
public CounterResult GetCurrentValue()
{
//Note: Some logic here
}
}
Now, this more-or-less works except that each time I make a call to the TestWcfServiceClient(), it uses the default constructor and creates a new instance of the Wcf Service and does not use the instance created by the windows service. This means that when I call GetCurrentValue() I get a null reference because the _service member hasn't been set.
I've looked around for solutions and found some citing ServiceHostFactory and ServiceHost and IInstanceProvider but each has seemed to be very, very complicated.
Any thoughts you could provide would be most appreciated.
EDIT: Here's my ServiceModel info
<system.serviceModel>
<services>
<service name="WcfService.TestWcfService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8733/Design_Time_Addresses/WcfService/TestWcfService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="basicHttpBinding" contract="WcfService.ITestWcfService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
WCF is VERY extensible, but in order to provide such extensibility it is also very complicated. In my opinion, more than it should be so if you want to use this implementation that's the way to go. YOu have to create a behavior that changes the service factory so you can use the custom constructor instead of the empty one.
However, I think there might be another alternative. Since both the service and the WCF share the same app domain they can share values through static objects.
I would move the logic that carries the value you want to expose to un underlying assembly (if you didn't already) and both the service and WCF service would see the same instance therefore you don't need to change all the WCF plumbing.
You are trying to put a square peg in a round hole.
WCF is explicitly designed to enable calling business logic independent of how it is hosted. You are trying to maintain the old remoting design that has your business logic in the host layer (in this case a Window's service). As a result you are asking to pass information back up to the host in a way that is possible in WCF but ugly and is generally avoided for many good reasons.
If you want a clean WCF design you will need to create abstraction layers and move your business logic out of the existing TestWindowsService class. Then the windows service creates the WCF service host, the WCF host creates the WCF service, and the WCF service is not dependent on the classes that host it.
Having said all that...
To actually answer your question:
Conceptually the code that you have written should work. Passing an object instance into the ServiceHost constructor is by far the easiest way to avoid the complexity of writing a custom IInstanceProvider. A couple of things to check:
When you pass a service instance into the ServiceHost constructor it needs to be marked as a singleton.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
Make sure that initialization is really working the way you think it is:
Put a guard on your TestService(ITestWindowsService) constructor that throws if service is null.
You have a comment on the default constructor for TestWcfService() that says "for discoverability". I would remove that constructor (at least while you are troubleshooting). A piece of code might be using that constructor to host a service instance you don't want. This is likely to cause your app to start throwing exceptions or compile errors that point out your real problem.
If you are still having problems: What does the Service Model section of your app.config look like?
Related
I have a standard Web Service that processes JSON requests via an webHttpBinding. I am trying to find out whether there is a limit on how many concurrent connections it can handle and how to control it. Can't find anything. I am missing something simple or some setting?
Here is a skeleton of my service:
[ServiceContract]
public interface IMyService {...}
[ServiceErrorBehavior(typeof(ErrorHandler))]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyService : IMyService {...}
I have some suggestion for this, but this will not be direct config related change. Hold on and read this.
In WCF, there is InstanceContextMode and ConcurrencyMode properties defined for ServiceBehavior. These parameters are configurable only within the service code, and not in XML configuration, because they relate to the runtime behavior of the service and the service developer should be aware of their values. The InstanceContextMode parameter determines how many instances of the service have to be created by the WCF runtime. The possible values are:
PerCall: a new InstanceContext object is created for each call.
PerSession: a new InstanceContext object is created for each session. If the channel does not create a session this value behaves as if it were PerCall.This is the default value.
Single: only one InstanceContext object is used for all incoming calls and is not recycled subsequent to the calls. If a service object does not exist, one is created.
More helpful Blog
Use WCF Service Throttling to control the service.
<behaviors>
<serviceBehaviors>
<behavior name="Throttled">
<serviceThrottling
maxConcurrentCalls="1"
maxConcurrentSessions="1"
maxConcurrentInstances="1"
/>
</behavior>
</serviceBehaviors>
</behaviors>
Always remember that service behaviors do not override limits defined in the host (or binding). For example when using webHttpBinding the default IIS Maximum Concurrent Connections would likely need to be changed for large concurrency values.
Turns out it has more to do with threading than anything else. The default ASP.NET settings are pretty conservative, so you have to hike them up. Once I did that, the concurrent connections bottleneck completely disappeared.
Make sure you have the following in the appropriate machine.config (not web.config):
<configuration>
<system.net>
<connectionManagement>
<add address="*" maxconnection="100" />
</connectionManagement>
</system.net>
<system.web>
<processModel
autoConfig="true"
maxWorkerThreads = "100"
maxIoThreads = "100"
minWorkerThreads = "50"
minIoThreads = "50"
/>
<httpRuntime
minFreeThreads="176"
minLocalRequestFreeThreads="152"
/>
</system.web>
</configuration>
I took all this info from Tuning IIS article by Stuart Brierley. The only thing I changed significantly from his recommendations is maxConnection value.
We have a 3rd party vendor service and an in-house service to communicate with it. Everything works perfectly with our in-house service, but I've been asked to write a fall back clone of our vendor's service. The intention is to be able to run up our clone, swap-out the client end-point and allow our in-house service to continue testing against the clone.
Is it possible to recreate/mimic a service such that an existing client can communicate with it (without modification) as if it were the original service?
So far I’ve tried 3 things and none of them work.
1st approach
Create a simple service, reference the 3rd party service to gain access to the custom types and mimic the [operation Contract]’s.
When I try to communicate with this service I get the following error.
A first chance exception of type 'System.ServiceModel.ActionNotSupportedException' occurred in System.ServiceModel.dll
Additional information: The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
There is no security requirements as we are using basic http (no ssl). The service model portion of the config file and the service behaviour class attributes are below:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="SimpleBinding" />
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="cloneBehavior" name="MyClone">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="SimpleBinding"
contract="MyService.IMyService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/clone/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="cloneBehavior">
<serviceMetadata httpGetEnabled="True" httpGetUrl="http://localhost/clone/mex" />
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
and the service behaviour
[ServiceBehavior(Name = "CloneService",
ConfigurationName = "MyClone",
InstanceContextMode = InstanceContextMode.PerCall,
AddressFilterMode = AddressFilterMode.Any)]
public class MyService : IMyService
{
Everything looks good and I have come to my first dead end.
2nd approach
Get rid of my interface/service contract and inherit directly from the interface generated in the reference.cs file.
When I run this service up, I get the following error
System.InvalidOperationException: The operations myMethodA and myMethodB have the same action (). Every operation must have a unique action value.
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ActionDemuxer.Add(String action, DispatchOperationRuntime operation)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime..ctor(DispatchRuntime dispatch)
at System.ServiceModel.Dispatcher.DispatchRuntime.GetRuntimeCore()
at System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpened()
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at Microsoft.Tools.SvcHost.ServiceHostHelper.OpenService(ServiceInfo info)
Taking a look at the generated interface for this method, they are all decorated with the following attribute:
[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="*")]
My understanding from msdn is that WCF defaults to adding a unique action of the pattern <namespace>/<service>/<operation>[Response].
If I try setting the action to * then I can hit the service (as expected with the catch all / unmatched message handler), but I can't hit a specific method.
Nevertheless, manually making all the actions unique (and conforming to the above pattern), give this error:
The contract ‘IMyService’ in client configuration does not match the name in service contract, or there is no valid method in this contract.
…
I have clearly defined methods in the service contract and have come to a second dead end.
3rd approach
Using the wsdl.exe tool to generate a service from the wsdl. I followed the instructions from this SO post to generate an interface and inherit from it.
I’ve also tried generating the service itself by using the clientWsdl.wsdl /l:CS /server command and following the instructions in this post.
After tidying up the generated code and running it up, I’m back to my original error:
A first chance exception of type 'System.ServiceModel.ActionNotSupportedException' occurred in System.ServiceModel.dll
Additional information: The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
At each attempt I have double checked all the config settings and updated the contract at each stage.
At this stage I'm wondering if it's even possible.
Were you ever able to mimic the service using WCF? I find myself in a similar situation where I've been tasked to write some integration tests where our method makes a call to a vendor's web service. I would have preferred to leverage Moq to write proper unit tests, but I'm constrained by 1) not being allowed to change the signature of the method that I'm testing, and 2) not really knowing anything about the web service itself except for what we send to the service and its expected response.
#jparram's suggestion was my next approach.
Note: I would have preferred to have posted this as a comment seeing that I'm not really answering your question.
If I understand your scenario, I would create wrapper service that decides which service to call. It sounds like that's what you want to do with Scenario 1. So, your client would always be calling your wrapper service, and your wrapper service would map the inputs to the required inputs of your 3rd party service or your back up service.
The error you received sounds like an issue in the generation of the proxy client where the "Action" is not getting mapped. Take a look at the generated proxy code from a known working configuration and compare it to what is in your scenario 1.
Edit
Compare the generated proxy client of your service and the 'real' service. The complaint about the Action = "" is probably due to the:
[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="")]
On your client not getting mapped to the corresponding operation.
Is it possible to have one service with two behavior configurations? As you know it is possible to have one service and more than one endpoint where you can specify different binding configuration.
But I need to have, for the same service, different service behaviors.
If I try something like this:
<services>
<service name="Service.Service1" behaviorConfiguration="Behavior1">
<host>
<baseAddresses>
...
</baseAddresses>
</host>
<endpoint ...>
</endpoint>
</service>
<service name="Service.Service1" behaviorConfiguration="Behavior2">
<host>
<baseAddresses>
...
</baseAddresses>
</host>
<endpoint ...>
</endpoint>
</service>
</services>
... I got error "A child element named 'service' with same key already exists at the same configuration scope"
I know that I can create new class that inherits original service class but is there better solution?
Seems that you should register the same service class with another service name. Service behavior is a part of service configuration so if you want to use different behaviors you should configure different services. My question to you: if you will have one service with two behaviors, how wcf will decide to use this one or another?
Why you solution with inheritance is bad?
Quite intriguing question... I am not certain if what I am describing is possible but solution would be some thing like below:
Choose different name for service - there will be some scheme such as name="Service.Service1.Entry1"
Write custom ServiceHost (perhaps coupled with IInstanceProvider) that will ignore the last .Entry1 part and creates the service instance using Service.Service1 name.
Yet another way would be injecting dynamic type named "Service.Service1.Entry1" inherited from Service.Service1 when application is initializing. This part is very much possible - i.e. for every mentioned service, you would create n subtypes dynamically at app start-up so that you can use them as intended.
I have a quite simple WCF service method which returns an IQueryable, just for testing. Perhaps I got something wrong when trying to understand what IQueryable is designed for. I clearly plan to use this with the IQueryable provider of NHibernate later. But first I ran into some sort of serialization problems (at least I think it might be the problem) whenever using a WCF method returning an IQueryable. It doesn't even work for a simple string.
Here's my code:
public IQueryable<string> GetEquipmentConfigurations()
{
var returnValue = new List<string>();
returnValue.Add("test");
return returnValue.AsQueryable();
}
It might not have much sense, it's just for testing whether I really get those IQueryables over the wire using WCF. Whenever I call this method using a client like SoapUI I get a socket exception and a connection reset, just the same as if I was trying to return something that is not marked as DataContract. But the only thing I do here is trying to return some lousy string list. What's wrong with that?
I use basicHTTPBinding, here are my settings:
<system.serviceModel>
<services>
<service name="EquipmentConfigurationService" behaviorConfiguration="DefaultBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/Krones.KBase/Services/EquipmentConfigurationService"/>
</baseAddresses>
</host>
<endpoint address=""
binding="basicHttpBinding"
contract="Krones.MES.KBase.Public.Service.EquipmentDefinition.IEquipmentConfigurationService" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DefaultBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
The OperationContract attribute is set for the interface:
[OperationContract]
IQueryable<string> GetEquipmentConfigurations();
It all works well when just returning a simple string. Anyway I want to take profit from the IQueryable features using LINQ later.
Anybody any idea what's going wrong here?
Thanks and Cheers,
Stefan
The core WCF is designed to send data, not queries. Stick to returning List<Foo> etc; it'll save you much head-scratching.
However, you might have more luck doing what you are after with WCF Data Services, which allows you to expose IQueryable<> sources.
The way this works is that the tooling builds a client that exposes similar looking IQueryable<> hooks; when you query data, it represents the expression on the wire, queries the data and brings it back to the client. But it is still the results (not the query) that goes over the wire.
(Obsolete)
AFAIK it isn't possible out of the box to serialize IQueryable<> or Expression Trees (think about it - it would mean that the expression tree / lambda would need to be serialized and the function rebuilt)
However, where there is a will, it seems there is a way - you might want to look at projects such as this
http://code.msdn.microsoft.com/exprserialization
Edit : Note that times have changed - See WCF RIA Services as per Marc Gravell's post.
Good luck!
HTH
I am building an single application that uses WCF to call out to multiple external endpoints. All of the remote endpoints are identical except for the URI. I would like to treat them as a pool: add and remove endpoints through configuration and have the application understand what to do.
My original plan was to define one endoint in the app.config, then iterate over my list of endpoints and update client.Endpoint.Address on the fly to point to the right place. Unfortunately, that property is read-only, rendering that plan unworkable.
I'm a little bit stumped here. Any suggestions on how I might accomplish this?
How to: Create a Service Endpoint in Code shows you how to manage service endpoints in code rather than configuration.
Have you tried a separate name that is passed in to the client constructor?
<endpoint address="http://localhost:18000/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="MyServiceReference.IMyService" name="BasicHttpBinding_IMyService" />
<endpoint address="http://localhost:18001/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="MyServiceReference.IMyService" name="MyService_Secondary" />
<endpoint address="http://localhost:18002/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="MyServiceReference.IMyService" name="MyService_Tertiary" />
Store the end point addresses in a DB table and use Jason's suggestion for creating end points in code. When a new endpoint shows up you just add another row to the table and force the service to re-query the endpoint table.
How to: Create a Service Endpoint in Code
http://msdn.microsoft.com/en-us/library/ms731080.aspx