I have an application written in c# on .NET 4.0 which needs to make multiple web service requests. The web service requests vary in nature but are mostly requesting information.
The Types involved is a derivative of System.ServiceModel.ClientBase
The connection is setup in code and uses types such as BasicHttpBinding, EndpointAddress, and CustomBinding to name a few.
How can I determine the max number of concurrent requests that can be made on the derivative of the ClientBase?
I've not been able to find any property that pertains to MaxConnections but I do come across things like NetTcpBinding.MaxConnections and ConnectionManagementElement.MaxConnection but neither of these seem compatible with my leveraged APIs. Either I'm missing how to use them, this isn't available or I don't know where to look.
WCF is an abstraction on core networking concepts. For HTTP bindings, it falls under the ServicePoint configuration which determines things like your HTTP concurrent connection limits.
You want ServicePointManager.DefaultConnectionLimit for HTTP:
http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.defaultconnectionlimit.aspx
You can also do this via your config file:
http://msdn.microsoft.com/en-us/library/fb6y0fyc.aspx
This would be in the binding configuration section of the service host's .config file. Depending on the binding being used, you can set things like maxConcurrentCalls and maxConcurrentSessions, there are usually default limits for them imposed by WCF.
Real life example:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviorBasicHttp">
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentSessions="1000" maxConcurrentInstances="1000"/>
<serviceMetadata />
</behavior>
</system.serviceModel>
Or in code behind, something like this:
ServiceHost host = new ServiceHost(typeof(MyService));
ServiceThrottlingBehavior throttleBehavior = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 40,
MaxConcurrentInstances = 20,
MaxConcurrentSessions = 20,
};
host.Description.Behaviors.Add(throttleBehavior);
host.Open();
Taken from here: WCF: How do I add a ServiceThrottlingBehavior to a WCF Service?
Related
I want to use Slot Swapping on Azure for a WCF Service. I know that we can do the appSettings directly in Azure. I couldn't find an option to configure the system.serviceModel/client, but for slot swapping i need 3 endpoint configurations, one on each slot I have
<system.serviceModel>
<client>
<endpoint address="http://myservice-devslot.azurewebsites.net/ServiceName.svc" ... />
</client>
This would be the configuration for 1 slot, as it's shown in the address: dev-slot
Or is there an other approach to manage endpoints?
Ok, I configured the endpoint address through Code and added an EndPointAddress Key to the AppSettings. Now I can swap from TEST to INT etc by just do one click in Azure. Thanks everyone
wcfServiceClient.Endpoint.Address = new EndpointAddress(endPointAddress);
For editing config files depending on the destination environment you're going to deploy the application to, you'd usually use config transformations.
As you're looking to so using azure, have a look at this article by Brady Gaster as starting point. It describes the whole procedure quite detailed.
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.
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?
I am quite new with .NET, C# and WCF and I am trying to create a service that will expose methods to allow upload and download of a large amount objects (array of objects). I have seen a lot of posts regarding large file transfers in WCF, but I can't seem to find anything that focuses on just uploading and downloading large amounts of serializable objects.
I have been able to "hack up" the web.config file for the allowed bytes and timeout limit etc, but I am wondering if there are actually better ways to configure the WCF for better speed and memory usage to allow for such transmission. Because I have configured the web.settings based on my testing results (if time out/byte limit exceeded, increase the limit with some crazy large numbers etc) I doubt my configuration is making sense at all.
Second, I have seen some implementation options like having binding TransferMode = Streaming or MTOM, yet I don't know if they will apply to my scenario at all. Can someone please point me to the correct direction?
Sorry I might not have constructed my question well enough, but ideas will be much appreciated.
Below is my web.config settings:
<system.web>
<httpRuntime maxRequestLength="409600000" executionTimeout="360000"/>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHTTP" closeTimeout="00:01:00" receiveTimeout="01:00:00"
sendTimeout="01:00:00" maxBufferSize="655360000" maxReceivedMessageSize="655360000"
messageEncoding="Text" />
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="WebService.WebService">
<endpoint address="" behaviorConfiguration="BasicEndPoint" binding="basicHttpBinding"
bindingConfiguration="BasicHTTP" name="BasicHTTP" contract="WebService.IWebService" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="BasicEndPoint">
<dataContractSerializer maxItemsInObjectGraph="65536000" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="204800000" />
</requestFiltering>
</security>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
I would recommend to use Stream mode only for tasks like video/audio streaming or similar, when you really have stream on host and you really need receive stream on client.
For any other tasks i would use Buffer mode because it is really easier to use and becase many useful wcf features rely on buffering. Using streaming with enabled SOAP message-level security (for example), can probably eliminate speed benefits of streaming mode (if you ever had some).
In your case i would recommend you to perform some workaround. Check these steps:
Try to use compression. It can greatly improve speed and resource usage, but it can not guarantee that your amount of data always will be the same. Who knows if your array will be 100x larger next year? So you may return to this point one year later.
Replace your method returning one giant array with method returning only one element or a small range of them. Then replace one GetAllStuff() method call with one call of GetItemsCountForDownload() and appropriate number of calls of GetElementAtIndex(int index) (or GetElementsRange(int startIndex,int endIndex)). Anyway, at this poin you will have to find some balance between message size (for each call) and number of calls performed.
If your data can not be easily splitted into small equal parts (e.g. first element of array is 10kb, second is 15 kb and third is 338mb), then try to combine both methods together: serialize your array to disk, compress it whith splittig to some number of parts of acceptable size and then trasfer them one after another.
Try to make parameters of your algorithm ajustable. Put them in your config file, so it will be possible to tune splitting process and compression level on every deployment machine according to avaliable resources.
Another benefit of splitting data and downloading chunk by chunk easiness to build some error-handling layer. If connection is unstable and transfer fails for some reason you can try to redownload only one chuk instead of all the data.
Some tips on architecture
Find appropriate crossplatform compression algorithm. Definitely you can find one that meets your needs. Look at BZip2 for C# <-> Python and GZip for C# <-> Java.
Try to make your architecture clear enough for other programmers. You can make different methods for compressed data transfer and for uncopressed (GetElementsRange, GetElementsRangeGZip, GetElementsRangeBZip2). Or you can make one method with compression type paramether (GetElementsRange(int startIndex,int endIndex,string compressionType). Anyway, other programmer must be able understand what data he is receiving and how to control compression mode.
You can move data splitting parameter from config file to method definition, so client will be able to define it by himself.
You can go further and implement two step architecture. Step one: remote client defines parameters of request (all of them, including compression mode, splitting mode and all other). Step two: receiving data. How about tokens? Methods should look like:
string GetTokenForDataRequest(string compressionMode, int maxChunkSize); //additional parameters like dates range, account number an other are defined in this method only
int GetChunkCount(string token);
byte[] GetDataChunkAtIndex(string token, int index);
Here compressionMode may be "None","BZip2" or "GZip"; If maxChunkSize is 0 then disable splitting (all data will be sent in one chunk), else split data in chunks with size equal to maxChunkSize (the last one will be smaller than other). So approximate scenario would be like:
Remote client sends a data request with desired parameters.
You generate session id (a token), save parameters for this session and prepare data according to parameters. "Prepare data" means loading data according to request, creating temp folder, serializind data, creating chunk files and persisting paths for further usage.
Client recieves a token, that is used for all other methods for retrieving data.
Every time remote client request data chunk throu your methods you will know where it stored on hard disk, how many chunks left and so on - thanks to provided token and persisted info.
You can easily handle simultaneous data transfer session with several clients at one time with no efforts (just make shure you store data chunks in different temp files and folders)
Client is able to redownload any chunk and you will not have to load data from database (or wherever it comes from).
When transfer is complete, you can wipe temp data and free some resources.
Do not look at this as at only possible solution. Just google around a little bit and you will find your very own way to solve your task!
You can use streaming message transfer, but it has some limitations.
If the streaming isn't suitable for you, you can implement paging of data (or try existing implementations, like in WCF Data Services).