How to Implement custom authentication in WCF service - wcf

I would like to create WCF restful service for mobile application with custom authentication. First request should be login, specially client sending username, password and getting access token. Then all other requests should be check access token. Also for authentication I would like to use asp.net membership provider in other words to use Forms based authentication.

At first, we should configure the Asp.net SQL membership Provider. Then we should use Username/password security mode so that authenticate the client with custom credential.
Please refer to the below configuration.
<connectionStrings>
<add name="SqlConn" connectionString="server=myserver;database=aspnetdb;uid=sa;password=123456;" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<membership defaultProvider="SqlMembershipProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add
name="SqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="SqlConn"
applicationName="WcfService2"
enablePasswordRetrieval="false"
enablePasswordReset="false"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="true"
passwordFormat="Hashed" />
</providers>
</membership>
<roleManager enabled ="true"
defaultProvider ="SqlRoleProvider" >
<providers>
<add name ="SqlRoleProvider"
type="System.Web.Security.SqlRoleProvider"
connectionStringName="SqlConn"
applicationName="WcfService2"/>
</providers>
</roleManager>
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2"/>
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding>
<security mode="Message">
<message clientCredentialType="UserName"></message>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="SqlRoleProvider">
</serviceAuthorization>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="SqlMembershipProvider"/>
<serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="974ad39ff0b86210f5e7d661e56945ad5c2d3770"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="wsHttpBinding" scheme="http" />
</protocolMapping>
If we use WCF to create Restful Service, we should replace the WSHttpbinding with Webhttpbinding.
Before setup the connection string, we should install the asp.net sql membership provider. it ordinarily located in the “C:\Windows\Microsoft.NET\Framework64\v4.0.30319” folder.
Aspnet_regsql.exe utility.
Here is a simple tutorial.
http://mahedee.net/asp-net-membership-step-by-step/
Here is an official example.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/membership-and-role-provider
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-use-the-aspnet-membership-provider
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-use-the-aspnet-role-provider-with-a-service
Feel free to let me know if the problem still exist.

Here is my solution without service configuration. If you have configured asp-net membership provider in web.config.
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class SPHostedWCFService
{
[OperationContract]
[WebGet(UriTemplate = "Login?username={username}&password={password}", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
public void Login(string username, string password)
{
FormsAuthenticationTicket ticket = null;
MembershipProvider membershipProvider = GetMembershipProvider();
if (membershipProvider.ValidateUser(username, password))
{
SPUser user = RunWithEP.web.EnsureUser(username);
ticket = new FormsAuthenticationTicket( 1, username, DateTime.Now, DateTime.Now.AddDays(1), true, user.ID.ToString());
}
if (ticket != null)
{
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Current.Response.Cookies.Add(cookie);
}
else
{
HttpContext.Current.Response.Write("Username or password incorrect.");
}
}
[OperationContract]
[WebGet(UriTemplate = "DoWork", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[PrincipalPermission(SecurityAction.Demand, Authenticated = false)]
public string DoWork()
{
if (HttpContext.Current.Request.IsAuthenticated)
{
return "authenticated request";
}
else
{
HttpContext.Current.Response.Write("Username not authenticated.");
return "not authenticated request";
}
}
}
GetMembershipProvider() specific to may environment, specially I'm using in SharePoint.

Related

WCF service not show metadata on server (return 404), only locally it works

I have a problem with metadata (wsdl on service soap).
Locally everything works fine. and at the address https: // localhost / DataImportSoapService /? wsdl the wsdl is exposed.
Nothing is shown on the server. Return 404.
I state that I have other active services in WCF and that the other .svc are correctly exposed.
While this basicHttpBinding service with basic auth doesn't work.
So on the server I activated everything:
My web.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DatineoUser" value="zzzzzz" />
<add key="DatineoPass" value="xxxx" />
<add key="UrlServiceNewEra" value="https://xxxxx/common/importDataCarrier?satcode=datineo" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service behaviorConfiguration="MetadataBehavior" name="TA_service_library_BA.DataImportSoapService">
<endpoint address="datineoV1" binding="basicHttpBinding"
bindingConfiguration="wsHttpBinding_LargeBinding" name="EndpointAVeryBigSum_BasicAuthentication"
contract="TA_service_library_BA.IDataImportSoapService" />
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://localhost/DataImportSoapService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MetadataBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="TA_service_library_BA.ServiceAuthenticator, TA_service_library_BA"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="wsHttpBinding_LargeBinding" closeTimeout="00:05:00" openTimeout="00:05:00" receiveTimeout="00:15:00" sendTimeout="00:15:00" maxBufferSize="15728640" maxBufferPoolSize="15728640" maxReceivedMessageSize="15728640">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
</configuration>
My classes:
namespace TA_service_library_BA
{
public class ServiceAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
throw new SecurityTokenException("Username and password required");
if (!(userName == ConfigurationManager.AppSettings["DatineoUser"] && password == ConfigurationManager.AppSettings["DatineoPass"]))
throw new FaultException(string.Format("Wrong username ({0}) or password ", userName));
}
}
}
namespace TA_service_library_BA
{
// NOTA: è possibile utilizzare il comando "Rinomina" del menu "Refactoring" per modificare il nome di interfaccia "IDataImportService" nel codice e nel file di configurazione contemporaneamente.
[ServiceContract(Namespace = "http://sen.company.com")]
[XmlSerializerFormat]
public interface IDataImportSoapService
{
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare)]
PushResponse PushDataArray(PushData pushDataArray);
//++++++++++++++++++++++++++++++++++++++++++++++
}
}
namespace TA_service_library_BA
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
public class DataImportSoapService : IDataImportSoapService
{
public PushResponse PushDataArray(PushData pushDataArray)
{
PushResponse responsePush = new PushResponse();
try
{
string authkey = ConfigurationManager.AppSettings["DatineoUser"] + ":" + ConfigurationManager.AppSettings["DatineoPass"];
string encAuthkey = CommFun.Base64Encode(authkey);
WebRequest request = WebRequest.Create(ConfigurationManager.AppSettings["UrlServiceNewEra"]);
request.ContentType = "application/json";
request.Method = "POST";
request.Headers.Add("Authorization", "Basic " + encAuthkey);
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(pushDataArray);
streamWriter.Write(json);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
if (response.StatusCode.Equals(HttpStatusCode.OK) || response.StatusCode.Equals(HttpStatusCode.NoContent))
{
//istanzio la risposta contenitore
responsePush.success = true;
responsePush.message = responseString;
}
else
{
//istanzio la risposta contenitore
responsePush.success = false;
responsePush.message = responseString;
}
}
catch (Exception ex)
{
//istanzio la risposta contenitore
responsePush.success = false;
responsePush.message = ex.Message;
}
return responsePush;
}
}
}
Why do some projects expose at least the .svc while this last service gives me 404 to the .svc file?
Beyond this then I don't understand what the hell is wrong with the configuration ... with IIS express everything goes .. on the server no.
Thanks for your help. I've been banging my head for a week and a half. I have tried the impossible. Tnx
You can check the following conditions:
Whether the permission of the managed directory is granted.
Whether the.NET version matches.
Is there a valid certificate on the site.
Try to put the image in the same path and find it.

Wcf returns "success" just for first time and subsequent calls return "timeout"

I researched this problem but i couldn't find any useful result.
I tried to configure web.config and iis configurations (disabling cache etc.) but result is negative.
When i make request as restful using wcf, some of wcf methods works fine for everytime but some of wcf methods work just first time returning success, subsequent calls' results return "timeout".
When i restart iis and , i end iis worker task on the task manager and i debug wcf service, troubled methods work fine just first time.
Please help me
Thank you in advance
For Ex:
[REQUEST] localhost/Service1.svc/GetData?value=8
[RESPONSE] "You entered: 8"
GetData method already works fine
but for Arm method;
[REQUEST first] localhost/Service1.svc/Arm?pass=1234&type=2
[RESPONSE first] {"Data":true,"Error":false,"Message":"Success"}
[REQUEST subsequents] localhost/Service1.svc/Arm?pass=1234&type=2
[RESPONSE subsequents] {"Data":false,"Error":true,"Message":"Request timeout. Please try again later"}
---Service1.svc.cs---
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1 : IService1
{
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "GetData?value={value}")]
//stable method
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "Arm?pass={pass}&type={type}")]
//troubled method
public ReturnType<bool> Arm(string pass, int type)
{
ParadoxFunctions pf = new ParadoxFunctions(pass);
ReturnType<bool> ret = new ReturnType<bool>();
ParadoxReturn pr = pf.ArmPanel(type);
if (pr.Success)
{
ret.Error = false;
ret.Message = pr.Message;
ret.Data = true;
}
else
{
ret.Message = pr.Message;
}
return ret;
}
}
---Web.config---
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>
<system.webServer>
</system.webServer>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<httpRuntime targetFramework="4.0" requestValidationMode="2.0" maxRequestLength="65536000"/>
<pages validateRequest="false" />
<httpModules>
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"/>
</httpModules>
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding maxReceivedMessageSize="65536000" transferMode="StreamedRequest">
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp defaultOutgoingResponseFormat="Json"/>
</behavior>
</endpointBehaviors>
<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>
<protocolMapping>
<add binding="webHttpBinding" scheme="http"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" minFreeMemoryPercentageToActivateService="0" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="ApplicationInsightsWebTracking"/>
</modules>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
<validation validateIntegratedModeConfiguration="false"/>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

WCF authentication is not working

I am using Message Security for WCF authentication. And my clientCredentialType="UserName".
Even if I am not providing valid username and password while accessing a service, it is working fine.
It should do authentication, If credentials are correct then only it should allow to access.`enter code here
The code is as follows:
WCF service behaviour section:
<behaviors>
<serviceBehaviors>
<behavior name="AuthenticationBehaviour">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfServiceAuthentication.Authenticator, WcfServiceAuthentication"/>
</serviceCredentials>
<!-- 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>
WCF Service Binding section in Web.config
<bindings>
<wsHttpBinding>
<binding name="Binding1">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
My authentication class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IdentityModel.Selectors;
using System.ServiceModel;
using log4net;
using System.Reflection;
namespace WcfServiceAuthentication
{
public class Authenticator : UserNamePasswordValidator
{
private static ILog _logger = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public override void Validate(string userName, string password)
{
_logger.Info("Validate called with username:" + userName + " and password:" + password);
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!(userName == "Admin" && password == "Admin123"))
{
// This throws an informative fault to the client.
throw new FaultException("Unknown Username or Incorrect Password");
}
_logger.Info("End called");
}
}
}
My Authentication service
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class AuthenticationService : IAuthenticationService
{
public int add(int num1, int num2)
{
return (num1 + num2);
}
}
}
And Client application:
AuthenticationServiceClient proxy = new AuthenticationServiceClient();
//proxy.ClientCredentials.UserName.UserName = "Admin";
//proxy.ClientCredentials.UserName.Password = "Admin123";
int addition= proxy.add(10, 10);
return View();
Here even though I am not providing credentials, Add method is working fine. It should ask for Authentication.
Modify the web config by adding the below tags to enable authentication service.
<system.web.extensions> <scripting>
<webServices>
<authenticationService enabled="true"
requireSSL = "true"/>
</webServices> </scripting> </system.web.extensions>
It should be added to the web config file. The sample is as here
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true"
requireSSL = "true"/>
</webServices>
</scripting>
</system.web.extensions>
<system.serviceModel>
<services>
<service name="System.Web.ApplicationServices.AuthenticationService"
behaviorConfiguration="AuthenticationServiceTypeBehaviors">
<endpoint contract=
"System.Web.ApplicationServices.AuthenticationService"
binding="basicHttpBinding"
bindingConfiguration="userHttps"
bindingNamespace="http://asp.net/ApplicationServices/v200"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="userHttps">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="AuthenticationServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment
aspNetCompatibilityEnabled="true"/>
</system.serviceModel>

Enabling WCF Help page changes response from JSON to XML

I'm working on creating a WCF web service that communicates via JSON. I got the service to a point that it's working and I'm trying to set up the help page so the developers that will consume the service can have some documentation to work by.
The issue that I'm running into is that when I did get the help page up and running, all the responses being sent out by my service changed from JSON to XML.
I'll be the first to admit that I'm very new to this. There might be some fundamental flaw with how I've structured my service, or it might be as simple as a flag I missed in the web.config... I'm really at a loss at this point.
What I found, through basically just trial and error and beating my head against the wall, was if I change the name attribute of the following line in the Web.config:
<standardEndpoint name="serviceEndpoint" helpEnabled="true" automaticFormatSelectionEnabled="true">
To be empty string:
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true">
The help page magically shows up, but my services are now spitting out XML instead of JSON.
I think it's probably better to over-share than to under-share for something as specific as this, so here's what I think is the relevant bits of the set-up. I apologize for the mono-tone code, I can edit it to be more readable if I figure out how.
Service Interface:
[OperationContract]
[Description("DESCRIPTIONATION HAPPENS")]
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "GetYears")]
GetYearsReply GetYears();
...
Service Implementation:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MPG : IMPG
{
public GetYearsReply GetYears()
{
GetYearsReply reply = new GetYearsReply();
reply.YearList = generateYears();
return reply;
}
...
Global.asax:
<%# Application Codebehind="Global.asax.cs" Inherits="MPG_Service.Global" Language="C#" %>
Global.asax.cs:
namespace MPG_Service
{
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
RouteTable.Routes.Add(new ServiceRoute("garage", new WebServiceHostFactory(), typeof(MPG)));
}
}
}
Web.config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
</system.webServer>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<standardEndpoints>
<webHttpEndpoint>
<!--
Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
via the attributes on the <standardEndpoint> element below
-->
<standardEndpoint name="serviceEndpoint" helpEnabled="true" automaticFormatSelectionEnabled="true">
<!--<security mode="Transport">
<transport clientCredentialType="None"/>
</security>-->
</standardEndpoint>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
</configuration>
If anyone has any insight into why this behavior is happening, or any other major screw-ups in my code I'd love any input.
Your client is saying that it accepts XML (application/xml), so that's what WCF is returning. That is consistent with the Automatic Formatting rules (see details at http://msdn.microsoft.com/en-us/library/ee476510.aspx). If you don't want that behavior, then set autoFormatSelectionEnabled to false in your configuration.

aspNetCompatibilityEnabled="true"

I have made a Azure web app that has a ASP.NET web that also contains some JSON WCF services. I really don't know enough about WCF service models to be sure that I'm doing it right, does this look correct to you? Are there other service model configurations that is better for scalability, more maximum concurrent connections, etc?
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.net>
<settings>
<!-- See http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 -->
<servicePointManager expect100Continue="false" />
</settings>
</system.net>
This works but I occasionally get unexpected connection drops (timeouts) with no HTTP error codes in my development environment which worries me.
Update # 24. Nov. 2011
web.config
<system.net>
<connectionManagement>
<!-- See http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 -->
<add address="*" maxconnection="48" />
</connectionManagement>
</system.net>
I'm suspecting that it may be the Visual Studio web server that causes the Ajax calls to get timeouts, after some minutes the service starts to accept requests again. Here is my complete setup, can you see what the problem is? I only have a single Ajax call to the service.
Inferface
IExample.cs:
using System.ServiceModel;
using System.ServiceModel.Web;
namespace WebPages.Interfaces
{
[ServiceContract]
public interface IExample
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json)]
string GetSomething(string id);
}
}
ExampleService.svc.cs markup
<%# ServiceHost Language="C#" Debug="true" Service="WebPages.Interfaces.ExampleService" CodeBehind="ExampleService.svc.cs" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
ExampleService.svc.cs codebehind
namespace WebPages.Interfaces
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ExampleService : IExample
{
string JsonSerializeSomething(Something something)
{
var serializer = new DataContractJsonSerializer(something.GetType());
var memoryStream = new MemoryStream();
serializer.WriteObject(memoryStream, something);
return Encoding.Default.GetString(memoryStream.ToArray());
}
public string GetSomething(string id)
{
var something = DoSomeBusinessLogic(id);
return JsonSerializeSomething(something);
}
}
}
jQuery call from client
function _callServiceInterface(id, delegate) {
var restApiCall = "Interfaces/ExampleService.svc/GetSomething?id="
+ escape(id);
$.getJSON(restApiCall, delegate);
}
function _getSomethingFromService() {
_callServiceInterface('123',
function (result) {
var parsedResult = $.parseJSON(result);
$('#info').html(result.SomethingReturnedFromServiceCall);
}
);
}
Update
I think I know what the problem is now; it seems that WCF services are single threaed by default ( source: http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SYSTEM.SERVICEMODEL.SERVICEBEHAVIORATTRIBUTE.CONCURRENCYMODE);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22);k(DevLang-CSHARP)&rd=true ) . That explain why my Ajax calls get timeouts, its blocked by another thread. This code should work a lot better:
ExampleService.svc.cs
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession,
IncludeExceptionDetailInFaults = false, MaxItemsInObjectGraph = Int32.MaxValue)]
//[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ExampleService : IExample
web.config
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding" bindingConfiguration="" />
</protocolMapping>
<behaviors>
<endpointBehaviors>
<behavior name="">
<webHttp defaultOutgoingResponseFormat="Json" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
ExampleService.svc
<%# ServiceHost Language="C#" Debug="true" Service="WebPages.Interfaces.TagService" CodeBehind="TagService.svc.cs" %>
Update # 9. Oct. 2011
I think I got the answer I needed here Locking with ConcurrencyMode.Multiple and InstanceContextMode.PerCall
aspNetCompatibilityEnabled="false" means not being able to access HttpContext, ASP.NET Sessions, etc. in my WCF code.
I think I got the answer I needed here Locking with ConcurrencyMode.Multiple and InstanceContextMode.PerCall
aspNetCompatibilityEnabled="false" means not being able to access HttpContext, ASP.NET Sessions, etc. in my WCF code.