WCF more than 50 concurent long running request - wcf

Hy, I have a WCF Test service, it does nothing only a thread.sleep(10000) and I call it from 200 clients.
The problem is the response time is greater and greater, after 10 minutes over 40 sec...
I have tired to change web.config and machine.config too.
We have Windows 2008 r2 and IIS 7.5
In my web.config
<serviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="400" maxConcurrentInstances="2000" />
In my macine.config
<processModel autoConfig="false" logLevel="None" maxIoThreads="1000" maxWorkerThreads="1000" minIoThreads="100" minWorkerThreads="100" />
In my Aspnet.config
<applicationPool maxConcurrentRequestsPerCPU="5000" maxConcurrentThreadsPerCPU="0" requestQueueLimit="5000" />
The WCF Service:
public interface ISampleService
{
[OperationContractAttribute]
string SampleMethod(string msg);
}
public class SampleService : ISampleService
{
public string SampleMethod(string msg)
{
Thread.Sleep(10000);
return msg;
}
}

Here my solution:
[ServiceContract(Namespace = "http://microsoft.wcf.documentation")]
public interface ISampleService
{
[OperationContract]
Task<string> SampleMethod(string msg);
}
public class SampleService : ISampleService
{
async Task<string> ISampleService.SampleMethod(string msg)
{
var task = Task.Factory.StartNew((param) =>
{
return "Return from Server : " + msg;
}, TaskContinuationOptions.LongRunning);
await Task.Delay(10000);
return await task.ConfigureAwait(false);
}
}
And i need only the web.config changes:
<serviceThrottling maxConcurrentCalls="500" maxConcurrentSessions="1000" maxConcurrentInstances="2000" />

Related

azure service fabric wcf endpoint address net.tcp instead of http

Trying to set up a stateful reliable service with wcf in service fabric, I have copied this sample code:
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new[] { new ServiceReplicaListener((context) =>
new WcfCommunicationListener<IService1>(
wcfServiceObject:this,
serviceContext:context,
endpointResourceName: "ServiceEndpoint",
listenerBinding: WcfUtility.CreateTcpListenerBinding()
)
)};
In ServiceManifest.xml I have declared the endpoint:
<Resources>
<Endpoints>
<Endpoint Name="ServiceEndpoint" Protocol="http" Port="8100" />
<Endpoint Name="ReplicatorEndpoint" />
</Endpoints>
</Resources>
But when I deploy to local cluster, and look at the node where the service is running in Service Fabric Explorer, the endpoint has this address:
net.tcp://localhost:8100/455d1c74-7734-449b-a567-47b749b3b822/88af6851-0285-4989-b0aa-c0cbe8c2d06a-131056235989980581
How do I get a http address?
On my team, we have been working with wcf in service fabric these days. Firstly, We tried to use WcfCommunicationListener form Microsoft.ServiceFabric.Services.Wcf but finally we decide to use our own implementation of ICommunicationListener in order to have a better control over the service host. We also use net.tcp as binding instead of http. We defined behaviors and endpoints programatically, not using app.config.
I am going to share our approach. Hope this can help you.
First step, the ICommunicationListener implementation:
public class ServiceHostCommunicationListener : ICommunicationListener
{
private string baseAddress;
public ServiceHost Host { get; set; }
public ServiceHostCommunicationListener(ServiceHost host, string baseAddress)
{
Host = host;
this.baseAddress = baseAddress;
}
public void Abort()
{
Host.Abort();
}
public async Task CloseAsync(CancellationToken cancellationToken)
{
try
{
await Task.Factory.FromAsync(Host.BeginClose(null, null), ar =>
{
Host.EndClose(ar);
});
}
catch (Exception)
{
Host.Abort();
}
}
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
return Task.Factory.FromAsync(Host.BeginOpen(null, null), ar =>
{
Host.EndOpen(ar);
return baseAddress;
});
}
}
Second step, create instance of the listener inside CreateServiceInstanceListeners inside our Service Fabric Service. Here is where I created a service host instance, its endpoints and behaviours.
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
yield return new ServiceInstanceListener(context =>
{
return CreateListener(context);
});
}
private ICommunicationListener CreateListener(StatelessServiceContext context)
{
Uri baseUri = new Uri($"net.tcp://{configuration.Network.BaseAddress}");
ServiceHost serviceHost = new ServiceHost(new SampleService(), baseUri);
InitServiceDebugBehavior(serviceHost);
if (configuration.Network.MetadataAddress != null)
{
AddMetadataEndpoint(baseUri, serviceHost);
}
InitServerCertificate(serviceHost);
AddServiceEndpoint(serviceHost);
return new ServiceHostCommunicationListener(serviceHost, baseUri.AbsoluteUri);
}
private void InitServiceDebugBehavior(ServiceHost host)
{
var serviceDebug = host.Description.Behaviors.Find<ServiceDebugBehavior>();
if (serviceDebug == null)
{
serviceDebug = new ServiceDebugBehavior();
host.Description.Behaviors.Add(serviceDebug);
}
serviceDebug.IncludeExceptionDetailInFaults = configuration.ServiceBehavior.ServerDebug.IncludeExceptionDetailInFaults;
}
private void AddMetadataEndpoint(Uri baseUri, ServiceHost serviceHost)
{
ServiceMetadataBehavior smb = serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior();
serviceHost.Description.Behaviors.Add(smb);
}
serviceHost.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
configuration.Network.MetadataAddress
);
}
private void InitServerCertificate(ServiceHost host)
{
var serverCertificateConfig = configuration.ServiceBehavior.ServerCertificate;
host.Credentials.ServiceCertificate.SetCertificate(
serverCertificateConfig.Store,
StoreName.My,
serverCertificateConfig.FindType,
serverCertificateConfig.FindValue
);
}
private void AddServiceEndpoint(ServiceHost serviceHost)
{
var binding = new NetTcpBinding(SecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
serviceHost.AddServiceEndpoint(typeof(SampleService), binding, configuration.Network.ServiceAddress);
}
Here is the configuration file, in case you have any doubts about it. We storage it inside PackageRoot-Config folder.
{
"Network": {
"BaseAddress": "localhost:1020/SampleService/",
"ServiceAddress": "service",
"MetadataAddress": "mex"
},
"ServiceBehavior": {
"ServerCertificate": {
"Store": "LocalMachine",
"FindType": "FindBySubjectDistinguishedName",
"FindValue": "CN=mycert.deploy.com"
},
"ServerDebug": {
"IncludeExceptionDetailInFaults": true
}
}
}
The only thing i can think of is manually create the Http binding based in this example:
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
SendTimeout = TimeSpan.MaxValue,
ReceiveTimeout = TimeSpan.MaxValue,
OpenTimeout = TimeSpan.FromSeconds(5),
CloseTimeout = TimeSpan.FromSeconds(5),
MaxReceivedMessageSize = 1024 * 1024
};
binding.MaxBufferSize = (int)binding.MaxReceivedMessageSize;
binding.MaxBufferPoolSize = Environment.ProcessorCount * binding.MaxReceivedMessageSize;
return binding;
With that binding the address is http in service fabric explorer

ServiceStack service metadata shows no operations

I am using ServiceStack for the first time on a brand-new project that started off as a ASP.NET MVC. I am hosting ServiceStack API at the root, so my web.config looks like this:
<system.web>
<httpHandlers>
<add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />
</handlers>
</system.webServer>
and my App_Start/RouteConfig.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("*");
}
Here's my service:
[Route("/catalogs/{ID}")]
[DataContract]
public class CatalogRequest : IReturn<Catalog>
{
[DataMember]
public int ID { get; set; }
}
[DefaultView("Catalogs")]
public class CatalogService : Service
{
public object Get(CatalogRequest request)
{
return (request.ID == 9999) ? new Catalog() { ID = 9999 } : null;
}
}
I use the following for testing:
public class TestAppHost : AppHostHttpListenerBase
{
public TestAppHost() : base("TestService", typeof(TestAppHost).Assembly) { }
public override void Configure(Funq.Container container)
{
IoC.Configure(container); // IoC is where all Funq configuration is done
}
}
In my VisualStudio unit test I start up the AppHost like this:
[TestClass]
public class TestHelper
{
public const string TEST_HOST_URL = "http://127.0.0.1:8888/";
private static TestAppHost __AppHost;
[AssemblyInitialize]
public static void Initialize(TestContext context)
{
// Start the test app host.
__AppHost = new TestAppHost();
__AppHost.Init();
__AppHost.Start(TEST_HOST_URL);
}
[AssemblyCleanup]
public static void Cleanup()
{
__AppHost.Dispose();
__AppHost = null;
}
}
When I run my test:
[TestMethod]
public void RequestCatalogByID()
{
var client = new JsonServiceClient(TestHelper.TEST_HOST_URL);
var request = new CatalogRequest() { ID = 9999 };
var response = client.Get(request);
Assert.IsNotNull(response);
}
I get a "Not Found" exception even though the URL seems to be correct: http://127.0.0.1:8888/catalogs/9999.
Pointing the browser to http://127.0.0.1:8888/metadata shows the metadata page with no operations.
What am I doing wrong?
Note the assembly you pass in your AppHost Base constructor should be where all your service implementations are (i.e. not your AppHost), so try instead:
public class TestAppHost : AppHostHttpListenerBase
{
public TestAppHost() : base("TestService", typeof(CatalogService).Assembly){}
...
}

WCF data services custom basic authentication

I have an WCF Data Service in .NET and I am consuming this service with datajs in Phonegap. I am trying to implement authentication as decribed here: http://goo.gl/0xQvC, and sending credentials with OData.read method. When I read credentials in the service with HttpContext.Current.Request.Headers["Authorization"], I found they are empty. What I am doing wrong?
Service Code:
[ServiceBehavior( IncludeExceptionDetailInFaults = true )]
public class TeyunaDataService : DataService< Meteora.TeyunaServices.Models.TeyunaContext >
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Clientes", EntitySetRights.AllRead );
config.SetEntitySetAccessRule("Transacciones", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.UseVerboseErrors = true;
}
public TeyunaDataService()
{
this.ProcessingPipeline.ProcessingRequest += new EventHandler<DataServiceProcessingPipelineEventArgs>(OnRequest);
}
void OnRequest(object sender, DataServiceProcessingPipelineEventArgs e)
{
var auth = HttpContext.Current.Request.Headers["Authorization"]; //This is empty
}
}
}
Javascript Client code:
OData.read({ requestUri: url, user: "pruebausr", password: "passprb" },
function (data, request) {
// ... code to procesing data (It works fine)
}, function(err) {
$.mobile.hidePageLoadingMsg();
alert("Error al obtener clientes. " + err.message);
}
);
Service web.config here: https://gist.github.com/3746043
I am using:
WCF Data Services 5.
IIS Express.

Using a Custom Endpoint Behavior with WCF and Autofac

I'm trying to implement a UoW like shown here:
https://blog.iannelson.uk/wcf-global-exception-handling/
But I can't for the life of me figure out how to wire it up with Autofac. I have absolutely no idea where to start.
I've got WCF working fine with Autofac from using http://autofac.readthedocs.org/en/latest/integration/wcf.html
But to inject or add the IEndpointBehavior? No idea...
If there's a better way to implement a UoW I would like to hear.
Edit:
For now I've just done:
builder.RegisterType(typeof (UnitOfWork))
.As(typeof (IUnitOfWork))
.InstancePerLifetimeScope()
.OnRelease(x =>
{
Trace.WriteLine("Comitted of UoW");
((IUnitOfWork) x).Commit();
// OnRelease inhibits the default Autofac Auto-Dispose behavior so explicitly chain to it
x.Dispose();
});
Though I don't know if this is an acceptable way of doing it, seems like a hack :(
Edit2:
Doesn't seem like it's possible to run a UoW in WCF :/
Edit 3:
I've posted my solution here: http://www.philliphaydon.com/2011/11/06/unit-of-work-with-wcf-and-autofac/
I have found a solution to this problem, where the unit of work only will be committed if no errors is thrown.
Register the unit of work as InstancePerLifetimeScope in Autofac
builder.RegisterType(typeof (UnitOfWork))
.As(typeof (IUnitOfWork)).InstancePerLifetimeScope();
Then i have created a combined EndpointBehavior and a ErrorHandler.
public class UnitOfWorkEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
{
public void Validate(ServiceEndpoint endpoint)
{
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
var unitOfWorkInstanceHandler = new UnitOfWorkInstanceHandler();
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(unitOfWorkInstanceHandler);
endpointDispatcher.DispatchRuntime.InstanceContextInitializers.Add(unitOfWorkInstanceHandler);
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
protected override object CreateBehavior()
{
return new UnitOfWorkEndpointBehavior();
}
public override Type BehaviorType
{
get { return typeof (UnitOfWorkEndpointBehavior); }
}
}
public class UnitOfWorkInstanceHandler : IInstanceContextInitializer, IErrorHandler
{
private bool _doCommit = true;
public void Initialize(InstanceContext instanceContext, Message message)
{
instanceContext.Closing += CommitUnitOfWork;
}
void CommitUnitOfWork(object sender, EventArgs e)
{
//Only commit if no error has occured
if (_doCommit)
{
//Resolve the UnitOfWork form scope in Autofac
OperationContext.Current.InstanceContext.Extensions.Find<AutofacInstanceContext>().Resolve<IUnitOfWork>().Commit();
}
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
_doCommit = false;
}
public bool HandleError(Exception error)
{
_doCommit = false;
return false;
}
}
The registration of the Endpoint Behavior in web.config
<system.serviceModel>
...
<extensions>
<behaviorExtensions>
<add name="UnitOfWork" type="Namespace.UnitOfWorkBehavior, Namespace"/>
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="">
<UnitOfWork/>
</behavior>
</endpointBehaviors>
...
</behaviors>
...
</system.serviceModel>

how to send status code as response for Unauthorized requests to WCF rest service

I am trying to develop a WCF rest servie which needs authorization using custom attribute.
I want to send the response as 401 status code if the authorization key is not valid in custom attribute which implements IOperationBehavior and IParameterInspector.
can any one tell me how to send the 401 status code as response from the custom attribute.
Here is the implementation
public class AuthorizationAttribute : Attribute,IOperationBehavior,
IParameterInspector
{
#region IOperationBehavior Members
public void ApplyDispatchBehavior(OperationDescription operationDescription,
System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
{
dispatchOperation.ParameterInspectors.Add(this);
}
#endregion
#region IParameterInspector Members
public object BeforeCall(string operationName, object[] inputs)
{
string publicKey =
WebOperationContext.Current.IncomingRequest.Header["Authorization"];
if (publicKey == "592F2D7E-5E9C-400D-B0AE-1C2603C34137")
{
}
else
{
// Here i would like to send the response back to client
with the status code
}
}
return null;
}
#endregion
}
[Authorization]
public bool signin(string username, string password)
{
}
Throw a WebFormatException
throw new WebFaultException(HttpStatusCode.Unauthorized);
If you're using WCF Rest Starter kit you can also do:
throw new Microsoft.ServiceModel.Web.WebProtocolException(System.Net.HttpStatusCode.Unauthorized, "message", ex);
That method has some more overloads if you need.
public string CreateError(int code ,string description)
{
Context.Response.StatusCode = code;
Context.Response.StatusDescription = description;
Context.ApplicationInstance.CompleteRequest();
return null;
}
Then from your web service methods just use this to return errors example:
return CreateError(403, "Request denied by server");
If aspnetcompatibilityMode cannot be enabled in your WCF services, then you can do as below.
You have to intercept the message and set the status code in HttpResponseMessageProperty in the wcf message. I use a CustomErrorHandler for doing that and it works fine.
public class CustomErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
fault.Properties[HttpResponseMessageProperty.Name] = new HttpResponseMessageProperty()
{
StatusCode = statusCode
};
}
}
Below code is for injecting CustomErrorHandler into the ServiceBehavior.
public class CustomServiceBehaviour : IServiceBehavior
{
... other IServiceBehavior methods
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
channelDispatcher.ErrorHandlers.Add(new CustomErrorHandler());
}
}
}
Then in web.config use the serviceBehavior
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="CustomServiceBehavior" type="MyNamespace.CustomServiceBehavior, MyAssembly" />
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name="CustomBehavior">
<CustomServiceBehavior />
</behavior>
</serviceBehaviors>
</behaviors>
<service behaviorConfiguration="CustomBehavior" name="SomeService">
<endpoint ..../>
</service>
</system.serviceModel>