I wanted to configure logging with SQL Server using ELMAH. I am getting following issue :
The content type text/html; charset=utf-8 of the response message does not match the content type of the binding (application/soap+xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 1024 bytes of the response were:
<!DOCTYPE html>
<html>
<head>
<title>Configuration Error</title>
<meta name="viewport" content="width=device-width" />
<style>
body {font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;}
p {font-family:"Verdana";font-weight:normal;color:black;margin-top: -5px}
b {font-family:"Verdana";font-weight:bold;color:black;margin-top: -5px}
.....
This as my service's web.config :
<configuration>
<configSections>
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
<section name="errorTweet" requirePermission="false" type="Elmah.ErrorTweetSectionHandler, Elmah" />
</sectionGroup>
</configSections>
<connectionStrings>
<add name="ADO.NET.SqlServer" connectionString="Data Source=MYDBSourceName;Initial Catalog=MYDatabaseName;Persist Security Info=True;User ID=sa;pwd=sa providerName="System.Data.SqlClient" />
</connectionStrings>
<elmah>
<security allowRemoteAccess="1"/>
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ADO.NET.SqlServer" applicationName="GWM Service"/>
</elmah>
<appSettings file="localSettings.config">
</appSettings>
<system.net>
<mailSettings>
<smtp>
</smtp>
</mailSettings>
</system.net>
<system.web>
<httpHandlers>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
</httpModules>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<handlers>
<add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah"/>
</handlers>
<modules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
</modules>
</system.webServer>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<services>
<service behaviorConfiguration="behaviorAuthentication" name="MyServiceName">
<endpoint binding="wsHttpBinding" bindingConfiguration="bindingAuthentication" contract="MyServiceContractInterfaceName">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="behaviorAuthentication">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="bindingAuthentication" transactionFlow="false" sendTimeout="00:30:00" receiveTimeout="00:30:00">
<reliableSession enabled="true"/>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
This is located in another hosting layer project. where as my service classes and contracts are in another project. they are mapped together for self hosting.
I added following class and attributes :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Collections.ObjectModel;
using System.Net;
using System.Web;
using System.IO;
using Elmah;
namespace Logging
{
public class ElmahErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return false;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (error == null)
{
return;
}
if (HttpContext.Current == null)
{
return;
}
Elmah.ErrorSignal.FromCurrentContext().Raise(error);
}
}
public class ServiceErrorBehaviorAttribute : Attribute, IServiceBehavior
{
Type errorHandlerType;
public ServiceErrorBehaviorAttribute(Type errorHandlerType)
{
this.errorHandlerType = errorHandlerType;
}
public void AddBindingParameters(ServiceDescription serviceDescription,
System.ServiceModel.ServiceHostBase serviceHostBase,
System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
IErrorHandler errorHandler;
errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = cdb as ChannelDispatcher;
cd.ErrorHandlers.Add(errorHandler);
}
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}
public class HttpErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return false;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
//if (error != null) // Notify ELMAH of the exception.
//{
// Elmah.ErrorSignal.FromCurrentContext().Raise(error);
//}
if (error == null)
return;
if (HttpContext.Current == null) //In case we run outside of IIS
return;
Elmah.ErrorSignal.FromCurrentContext().Raise(error);
}
}
}
In my service layer rather hosting layer. And decorated my service class with :
[ServiceErrorBehavior(typeof(HttpErrorHandler))]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
Now purposely I added ab exception in my service method. But while executing I got the exception as I mentioned above. Can somebody help me out please?
Related
I have a problem to make my WCF websocket service working. Until now I cannot find how to establish a connection. Both client and server side are really simple. So I think I miss something obvious here.
I currently have one WCF service running properly in my solution. The web services are hosted under IIS, the connection is properly handled using https and using basic authentication.
Here is my web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Forms" />
</system.web>
<system.serviceModel>
<!--webHttpBinding allows exposing service methods in a RESTful manner-->
<services>
<service behaviorConfiguration="secureRESTBehavior" name="MyApp.Services.MyService">
<endpoint address="" behaviorConfiguration="RESTfulBehavior" binding="webHttpBinding" bindingConfiguration="webHttpTransportSecurity" contract="MyApp.Services.IMyService" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<!--WCF Service Behavior Configurations-->
<behaviors>
<endpointBehaviors>
<behavior name="RESTfulBehavior">
<webHttp defaultBodyStyle="WrappedRequest" defaultOutgoingResponseFormat="Json" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="secureRESTBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="Custom" serviceAuthorizationManagerType="MyApp.Security.CustomAuthorizationManager, MyApp">
<authorizationPolicies>
<add policyType=" MyApp.Security.AuthorizationPolicy, MyApp" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
</behaviors>
<!--WCF Service Binding Configurations-->
<bindings>
<webHttpBinding>
<binding name="webHttpTransportSecurity" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" transferMode="Streamed" sendTimeout="00:05:00">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport" />
</binding>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="CORSModule" type="Security.CORSModule" />
</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" />
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://myapp.com" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Authorization" />
<add name="Access-Control-Allow-Methods" value="GET, DELETE, POST, PUT, OPTIONS" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Now I'm trying use WebSocketHost to host a WebSocket server as a WCF service.
Here is my factory:
public class TRWebSocketServiceFactory: ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
try
{
WebSocketHost host = new WebSocketHost(serviceType, baseAddresses);
host.AddWebSocketEndpoint();
return host;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
}
}
Here is the service:
public class EchoWSService : WebSocketService
{
public override void OnOpen()
{
this.Send("Welcome!");
}
public override void OnMessage(string message)
{
string msgBack = string.Format(
"You have sent {0} at {1}", message, DateTime.Now.ToLongTimeString());
this.Send(msgBack);
}
protected override void OnClose()
{
base.OnClose();
}
protected override void OnError()
{
base.OnError();
}
}
Here is my Global.asax file:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add(new ServiceRoute(
"Echo", new TRWebSocketServiceFactory(), typeof(EchoWSService)));
}
}
Here is the client side who try to establish a connection:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>WebSocket Chat</title>
<script type="text/javascript" src="Scripts/jquery-2.0.2.js"></script>
<script type="text/javascript">
var ws;
$().ready(function () {
$("#btnConnect").click(function () {
$("#spanStatus").text("connecting");
ws = new WebSocket("wss://MyServer/Echo");
ws.onopen = function () {
$("#spanStatus").text("connected");
};
ws.onmessage = function (evt) {
$("#spanStatus").text(evt.data);
};
ws.onerror = function (evt) {
$("#spanStatus").text(evt.message);
};
ws.onclose = function () {
$("#spanStatus").text("disconnected");
};
});
$("#btnSend").click(function () {
if (ws.readyState == WebSocket.OPEN) {
ws.send($("#textInput").val());
}
else {
$("#spanStatus").text("Connection is closed");
}
});
$("#btnDisconnect").click(function () {
ws.close();
});
});
</script>
</head>
<body>
<input type="button" value="Connect" id="btnConnect" /><input type="button" value="Disconnect" id="btnDisconnect" /><br />
<input type="text" id="textInput" />
<input type="button" value="Send" id="btnSend" /><br />
<span id="spanStatus">(display)</span>
</body>
</html>
On the line:
host.AddWebSocketEndpoint();
I always got the error:
Could not find a base address that matches scheme http for the endpoint with binding CustomBinding. Registered base address schemes are [https].
I'm a bit confused about the following points:
how to fix this error?
should I exose the EchoWSService in my web.config file as other services?
how the basic authentication is managed with web sockets?
Thanks!
I was missing:
Binding binding = WebSocketHost.CreateWebSocketBinding(true);
before:
host.AddWebSocketEndpoint();
Now the endpoint is correct.
How can I receive multipart form data in a WCF Service? I have uploaded it using the phone gap file transfer plugin upload function.
Below are the two functions that I'm trying to call:
///<summary>
///Method for file upload
///</summary>
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "Upload")]
string Upload(Stream data);
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped, Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "UploadImage")]
string UploadImage();
// TODO: Add your service operations here
I successfully hit the UploadImage function but I don't know how to read a file from the uploaded data.
When I try
HttpPostedFile file = HttpContext.Current.Request.Files["recFile"];
I get the error:
HttpContext.Current.Request.Files 'HttpContext.Current.Request.Files' threw an exception of type 'System.Web.HttpException' System.Web.HttpFileCollection {System.Web.HttpException}
base {"This method or property is not supported after HttpRequest.GetBufferlessInputStream has been invoked."}
This is my web.config file:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<customErrors mode="RemoteOnly"/>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="CacheFor10Seconds" duration="10"
varyByParam="none" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
<httpRuntime maxRequestLength="2000000000"/>
</system.web>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="false" />
</appSettings>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithJsonP"
crossDomainScriptAccessEnabled="true" maxBufferSize="2000000000"
maxReceivedMessageSize="2000000000"
transferMode="Streamed" />
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="Service.Service1">
<endpoint name="mexHttpBinding"
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"
/>
<endpoint address="" behaviorConfiguration="webHttpBehavior"
binding="webHttpBinding"
bindingConfiguration="webHttpBindingWithJsonP"
contract="Service.IService1" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
I got the problem it with the Wcf version targetFramework="4.5" issue ,
you have to add below code in web config than the issue get resolve:
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="false" />
<add key="wcf:serviceHostingEnvironment:useClassicReadEntityBodyMode" value="true" />
</appSettings>
my all the other web Config that i post already here is working fine below is the updated web config setting
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<customErrors mode="RemoteOnly"/>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="CacheFor10Seconds" duration="10"
varyByParam="none" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
<httpRuntime maxRequestLength="2000000000"/>
</system.web>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="false" />
<add key="wcf:serviceHostingEnvironment:useClassicReadEntityBodyMode" value="true" />
</appSettings>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithJsonP"
crossDomainScriptAccessEnabled="true" maxBufferSize="2000000000"
maxReceivedMessageSize="2000000000"
transferMode="Streamed" />
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="Service.Service1">
<endpoint name="mexHttpBinding"
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"
/>
<endpoint address="" behaviorConfiguration="webHttpBehavior"
binding="webHttpBinding"
bindingConfiguration="webHttpBindingWithJsonP"
contract="Service.IService1" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
This is my Service and IService Code:
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped, Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "UploadImage")]
string UploadImage();
#region
///<summary>
///Metohd to upload image.
///</summary>
public string UploadImage()
{
string JsonString = string.Empty;
JsonString = AppDomain.CurrentDomain.BaseDirectory;
try {
HttpPostedFile file = HttpContext.Current.Request.Files[0];
;
if (file == null)
{
RC.ErrorLog.LogFileWrite("<Exception>File is null</Exception>" + JsonString);
return JsonString;
}
string targetFilePath = AppDomain.CurrentDomain.BaseDirectory + #"Images\Upload" + Guid.NewGuid() + file.FileName.ToString();
file.SaveAs(targetFilePath);
return file.FileName.ToString();
}
catch(Exception e)
{
string errorMessage = RC.ErrorLog.CreateErrorMessage(e);
RC.ErrorLog.LogFileWrite(errorMessage+JsonString);
return JsonString;
}
}
#endregion
And below is my JqueryMobile code for PhoneGap
// A button will call this function
//
function captureImage() {
// Launch device camera application,
// allowing user to capture up to 2 images
debugger;
navigator.device.capture.captureImage(captureSuccess, captureError, { limit: 2 });
}
function captureSuccess(mediaFiles) {
var i, len;
for (i = 0, len = mediaFiles.length; i < len; i += 1) {
uploadFile(mediaFiles[i]);
}
}
// Called if something bad happens.
//
function captureError(error) {
var msg = 'An error occurred during capture: ' + error.code;
navigator.notification.alert(msg, null, 'Uh oh!');
}
function uploadFile(mediaFile) {
var ft = new FileTransfer();
path = mediaFile.fullPath;
name = mediaFile.name;
debugger;
// below varible contain the Server url name that i created by joining defenrent 3 var of //my application
var objUrl = _ServicesUrl._SecondServicePath + _ServicePage._BaseServicePage + _WcfFunctionUrl._ImageUpload;
alert("uploadImage");
ft.upload(path,
objUrl,
function (result) {
alert('Upload success: ' + result.responseCode);
alert(result.bytesSent + ' bytes sent');
debugger;
var abc = JSON.parse(result.Upload);
alert(abc);
},
function (error) {
alert('Error uploading file ' + path + ': ' + error.code);
},
{ fileName: name });
}
Hope the answer will help the community.
If a WCF service exposes three endpoints, then can we have different message inspectors for each endpoint? If yes then how can we apply on each endpoint?
First, you should create an endpoint behavior to apply a formatter you want.
class CustomInspectorEndpointBehavior : IEndpointBehavior
{
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomFormatter());
}
...
}
Or if there is a general logic, you can apply a behavior for each of the endpoints using a service behavior class:
class MultipleInspectorsServiceBehavior : IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
foreach (var endpoint in serviceDescription.Endpoints)
endpoint.EndpointBehaviors.Add(new CustomInspectorEndpointBehavior());
}
...
}
Finally, you can apply endpoint behaviors from code...
var host = new ServiceHost(typeof(TheService));
foreach (var endpoint in host.Description.Endpoints)
endpoint.EndpointBehaviors.Add(new CustomInspectorEndpointBehavior(c));
(in case of service behavior)
var host = new ServiceHost(typeof(TheService));
host.Description.Behaviors.Add(new MultipleInspectorsServiceBehavior());
...Or from config:
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="customInspectorEndpointBehavior"
type="CustomInspectorEndpointBehaviorExtensionElement, MyAssembly" />
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="behavior1">
<customInspectorEndpointBehavior />
<!--maybe some other behaviors-->
</behavior>
<behavior name="behavior2">
<customInspectorEndpointBehavior />
<!--maybe some other behaviors-->
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="TheService">
<endpoint address="address1" ... contract="..." behaviorConfiguration="behavior1" />
<endpoint address="address2" ... contract="..." behaviorConfiguration="behavior1" />
<endpoint address="address3" ... contract="..." behaviorConfiguration="behavior2" />
</service>
</services>
</system.serviceModel>
For service behavior:
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="multipleInspectorsServiceBehavior"
type="MultipleInspectorsServiceBehaviorExtensionElement, MyAssembly" />
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name="CustomServiceBehavior">
<multipleInspectorsServiceBehavior />
<!--maybe some others-->
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="TheService" behaviorConfiguration="ServiceBehavior">
<endpoint address="address1" ... contract="..." />
<endpoint address="address2" ... contract="..." />
<endpoint address="address3" ... contract="..." />
</service>
</services>
</system.serviceModel>
Here you should create a BehaviorExtensionElement to reference behaviors in the config:
class CustomInspectorEndpointBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get
{
return typeof(CustomInspectorEndpointBehavior);
}
}
protected override object CreateBehavior()
{
return new CustomInspectorEndpointBehavior();
}
}
class MultipleInspectorsServiceBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get
{
return typeof(MultipleInspectorsServiceBehavior);
}
}
protected override object CreateBehavior()
{
return new MultipleInspectorsServiceBehavior();
}
}
Based on the MSDN documentation I have created a custom UserNameSecurityTokenHandler and put in the CanValidateToken override and ValidateToken override. I thought I had configured the WCF web service to use the custom handler but the ValdiateToken never gets called. Here is the custom token handler:
public class CustomUserNameSecurityTokenHandler : UserNameSecurityTokenHandler
{
public override bool CanValidateToken
{
get { return true; }
}
public override ReadOnlyCollection<ClaimsIdentity> ValidateToken(SecurityToken token)
{
System.Diagnostics.Debugger.Launch();
if (token == null)
{
throw new ArgumentNullException();
}
var userNameToken = token as UserNameSecurityToken;
if (userNameToken == null)
{
throw new SecurityTokenException("Invalid token");
}
if ( userNameToken.UserName != userNameToken.Password )
{
throw new SecurityTokenException("Invalid username or password.");
}
var claims = new List<Claim>
{
new Claim(System.IdentityModel.Claims.ClaimTypes.Name, userNameToken.UserName),
new Claim(
"http://schemas.microsoft.com/ws/2008/06/identity/claims/ClaimTypes.AuthenticationInstant",
XmlConvert.ToString(DateTime.UtcNow, "yyyy-MM-ddTHH:mm:ss.fffZ"),
"http://www.w3.org/2001/XMLSchema#dateTime")
};
return new ReadOnlyCollection<ClaimsIdentity>(new List<ClaimsIdentity> {new ClaimsIdentity(claims, "Password")});
}
}
The debugger does not launch. The client code always fails when I call it.
Here is my WCF web.config entries for the site:
<configSections>
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<services>
<service name="WcfUserName.Service1">
<endpoint address="Service1.svc" binding="netHttpBinding"
contract="WcfUserName.IService1" />
<host>
<baseAddresses>
<add baseAddress="https://localhost/WcfUserName" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netHttpBinding>
<binding>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</netHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials useIdentityConfiguration="true" />
<serviceAuthorization principalPermissionMode="Always"/>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="netHttpBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
<system.identityModel>
<identityConfiguration name="identconfig">
<securityTokenHandlers>
<remove type="System.IdentityModel.Tokens.WindowsUserNameSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<add type="WcfUserName.Security.CustomUserNameSecurityTokenHandler, WcfUserName"/>
</securityTokenHandlers>
</identityConfiguration>
</system.identityModel>
I assume something is wrong with my configuration but cannot tell what it is. Any ideas?
AFAIK, you need to configure this correctly in web.config. This means you need to add you securitytokenhandler, but also remove the default username password handler. So you need to either <remove > the previous handler, or start over and <clear> the collection of securitytokenhandlers in the configuration file.
I am trying to set up a WCF Service but I'm having a few problems. The service works and loads the wsdl page when I type in
www.mydomain.com/Service1.svc
However when I use
www.mydomain.com/Service1.svc/
or try to use any of the get methods I get
The resource cannot be found.
Description: HTTP 404.
My web.config file is as follows
<?xml version="1.0"?>
<configuration>
<system.webServer>
<handlers>
<remove name="PageHandlerFactory-ISAPI-4.0"/>
<add name="PageHandlerFactory-ISAPI-4.0" path="*" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<remove name="ASP.NET-ISAPI-4.0-Wildcard"/>
<add name="ASP.NET-ISAPI-4.0-Wildcard"
path="*" verb="GET,HEAD,POST,DEBUG"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<remove name="svc-Integrated-4.0" />
<add name="svc-Integrated-4.0" path="*" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<validation validateIntegratedModeConfiguration="false"/>
</system.webServer>
<system.web>
<customErrors mode="Off"/>
<compilation debug="true" targetFramework="4.0">
</compilation>
<httpHandlers>
<remove verb="*" path="*.svc"/>
<add path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false" />
</httpHandlers>
</system.web>
<system.serviceModel>
<services>
<service name="RestService.Service1" behaviorConfiguration="ServiceBehaviour" >
<endpoint address="" binding="webHttpBinding" contract="RestService.IService1" behaviorConfiguration="web">
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://mydomain.com/Service1"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour" >
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
The Service.svc file is as follows :
namespace RestService
{
public class Service1 : IService1
{
public bool LoginUser( string Username, string password )
{
return true;
}
}
}
and the IService.cs is as follows:
namespace RestService
{
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
//BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "login/{username}/{password}")]
bool LoginUser(string username, string password);
}
}
The pipeline mode on the server is "Integrated" if that helps. I'm not sure what IIS version my hosting provider (pipeten) uses but I think it's 7.5 I have a feeling this has something to do with the URL validation however there is no option on my hosting to change this.
Okay turns out it was a simple mistake that I had made, I had missed out the . when adding the handler. Instead of path = "" it should have been path="."
<add name="ASP.NET-ISAPI-4.0-Wildcard"
path=".*" verb="GET,HEAD,POST,DEBUG"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />