WCF Authentication using basicHttpBinding and custom UserNamePasswordValidator? - c#

Here i am implementing custom usernamepasswordvalidator in WCF RESTfull service.What i need is while invoking this one http://localhost:12229/RestServiceImpl.svc/GetStudentObj through Chrome REST Client it is not validating the username password..it directly invoke this method and fetching the result.What am i doing wrong here??
My interface
[ServiceContract]
public interface IRestServiceImpl
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/GetStudentObj", RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
Student GetStudent();
}
SVC
public class RestServiceImpl : IRestServiceImpl
{
public Student GetStudent()
{
Student stdObj = new Student
{
StudentName = "Foo",
Age = 29,
Mark = 95
};
return stdObj;
}
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException("You must provide both the username and password to access this service");
}
if (!(userName == "user1" && password == "test") && !(userName == "user2" && password == "test"))
{
throw new SecurityTokenException("Unknown Username or Incorrect Password");
}
}
}
}
and Web.Config
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webHttpTransportSecurity">
<security mode="Transport">
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</webHttpBinding>
</bindings>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
<services>
<service name="RestService.RestServiceImpl" >
<endpoint address="" binding="webHttpBinding" contract="RestService.IRestServiceImpl"></endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior >
</endpointBehaviors>
<serviceBehaviors>
<behavior name="SecureRESTSvcTestBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="RESTfulSecuritySH.CustomUserNameValidator, RESTfulSecuritySH" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Any suggestion??

It seems that you didn't set the custom behavior for your service.
You need to tell the service about your SecureRESTSvcTestBehavior behavior by using the behaviorConfiguration attribute:
<service name="RestService.RestServiceImpl" behaviorConfiguration="SecureRESTSvcTestBehavior">
<endpoint address="" binding="webHttpBinding" contract="RestService.IRestServiceImpl"></endpoint>
</service>

Related

WCF protobuf endpoint 400 bad request

I have WCF service with DataContract json serialization. I would like to add service endpoints to consume Protobuf data messages.
I tried to use nugget package ProtoBuf.Services.WCF.
Added endpoint via web.config configuration. However, every request on protobuf endpoint with address "proto" returns 400 Bad request. Web.config sample is written bellow. Endpoint with default address "" works properly.
Get method:
HTTP 200 OK http://localhost:65460/BeaconService.svc/GetData
HTTP 400 BAD REQUEST: http://localhost:65460/BeaconService.svc/proto/GetData
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding transferMode="Streamed">
<security mode="None" />
</binding>
</webHttpBinding>
<basicHttpBinding>
<binding messageEncoding="Mtom">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<extensions>
<behaviorExtensions>
<add name="protobuf" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net" />
</behaviorExtensions>
</extensions>
<services>
<service behaviorConfiguration="DefaultServiceBehavior" name="Services.BeaconService">
<endpoint address="" behaviorConfiguration="httpBehavior" binding="webHttpBinding" contract="Services.IBeaconService" />
<endpoint address="proto" behaviorConfiguration="protoBehavior" binding="basicHttpBinding" contract="Services.IBeaconService" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="protoBehavior">
<protobuf />
</behavior>
<behavior name="httpBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</system.serviceModel>
Please, which part of configuration is defective. Eventualy, what is proper way to call Get method on "proto" WCF endpoint to avoid HTTP 400 Bad request message?
Unfortunately, I have failed to implement ProtoBuf.Services.WCF and decided to use another approach. In general, WCF by default uses DataContractSerializer.
After reading this article, I realized It is possible to replace this serializer with another one, f.e. protobuf serializer in this library. So I created behavior extension, which replaces DataContractSerializer with my custom ProtobufSerializer. In configuration added another endpoint, which has set behavior extension to use my custom ProtobufSerializer.
WebHttpBehavior:
public class ProtobufBehavior : WebHttpBehavior
{
protected override IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
return new ProtobufDispatchFormatter(operationDescription);
}
protected override IDispatchMessageFormatter GetReplyDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
return new ProtobufDispatchFormatter(operationDescription);
}
}
Dispatch formatter:
namespace Services.Extension.ProtobufSerializationExtension
{
public class ProtobufDispatchFormatter : IDispatchMessageFormatter
{
OperationDescription operation;
bool isVoidInput;
bool isVoidOutput;
public ProtobufDispatchFormatter(OperationDescription operation)
{
this.operation = operation;
this.isVoidInput = operation.Messages[0].Body.Parts.Count == 0;
this.isVoidOutput = operation.Messages.Count == 1 || operation.Messages[1].Body.ReturnValue.Type == typeof(void);
}
public void DeserializeRequest(Message message, object[] parameters)
{
if (!message.IsEmpty)
{
XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
bodyReader.ReadStartElement("Binary");
byte[] rawBody = bodyReader.ReadContentAsBase64();
MemoryStream ms = new MemoryStream(rawBody);
using (StreamReader sr = new StreamReader(ms))
for (int i = 0; i < parameters.Length; i++)
parameters[i] = Serializer.Deserialize(operation.Messages[i].Body.Parts[i].Type, sr.BaseStream);
}
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
byte[] body;
using (MemoryStream ms = new MemoryStream())
using (StreamWriter sw = new StreamWriter(ms))
{
Serializer.Serialize(sw.BaseStream, result);
sw.Flush();
body = ms.ToArray();
}
Message replyMessage = Message.CreateMessage(messageVersion, operation.Messages[1].Action, new RawBodyWriter(body));
replyMessage.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
return replyMessage;
}
class RawBodyWriter : BodyWriter
{
internal static readonly byte[] EmptyByteArray = new byte[0];
byte[] content;
public RawBodyWriter(byte[] content)
: base(true)
{
this.content = content;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("Binary");
writer.WriteBase64(content, 0, content.Length);
writer.WriteEndElement();
}
}
}
}
Extension element:
namespace Services.Extension.ProtobufSerializationExtension
{
public class ProtobufSerializationServiceElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(ProtobufBehavior); }
}
protected override object CreateBehavior()
{
return new ProtobufBehavior();
}
}
}
Web config:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding transferMode="Streamed">
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
<extensions>
<behaviorExtensions>
<add name="protobufExtension" type="Services.Extension.ProtobufSerializationExtension.ProtobufSerializationServiceElement, Services" />
</behaviorExtensions>
</extensions>
<services>
<service behaviorConfiguration="DefaultServiceBehavior" name="Services.BeaconService">
<endpoint address="" behaviorConfiguration="httpBehavior" binding="webHttpBinding" contract="Services.IBeaconService" />
<endpoint address="proto" behaviorConfiguration="protoBehavior" binding="webHttpBinding" contract="Services.IBeaconService" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="protoBehavior">
<webHttp/>
<protobufExtension/>
</behavior>
<behavior name="httpBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</system.serviceModel>
Services.Extension.ProtobufSerializationExtension is name of my custom namespace inside application structure. Hope this helps someone.

HttpModule in WCF project just works once

Please consider this code:
<system.web>
<compilation debug="true" targetFramework="4.6"/>
<httpRuntime targetFramework="4.5.2"/>
<authentication mode="None" />
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="MyNameSpace.Services.Service1" behaviorConfiguration="ServiceBehavior">
<endpoint binding="basicHttpBinding" contract="MyNameSpace.Services.ISrv"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpBinding" scheme="http"/>
</protocolMapping>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="AuthSecurity" type="MyNameSpace.CustomAuthorization" />
</modules>
<directoryBrowse enabled="true"/>
</system.webServer>
and the HttpModule code is:
namespace MyNameSpace
{
public class CustomAuthorization : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
CheckAccess();
}
private bool CheckAccess()
{
HttpContext c = HttpContext.Current;
if (HttpContext.Current.Handler != null) // <--Break Point
{
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
...
}
return false;
}
}
}
and in the client I wrote this code:
Service1client client = new Service1client();
client.ClientCredentials.UserName.UserName = "mmmm"
client.ClientCredentials.UserName.Password = "nnnn";
var tmp = client.DoWork(1);
the problem is after running the project, Service returns the correct result but HttpModule code didn't execute.
When I use a breakpoint in HttpModule it hits during Application_Start event. But after that it doesn't hit any more and its code doesn't execute.
Where is the problem?
Thanks
As I understand it, you defined just what to do at application start; if you want to check incoming requests, try to add these methods to your HttpModule and set breakpoints to check whether those methods are hit:
private void Application_BeginRequest(Object source,
EventArgs e)
{
CheckAccess();
}
private void Application_EndRequest(Object source, EventArgs e)
{
CheckAccess();
}
Of course you need to register those methods at application start:
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
application.EndRequest +=
(new EventHandler(this.Application_EndRequest));

WCF Error: The operation cannot be completed because the pipe was closed

I am getting an error when the client reference is used a second time for calling the underlying method. On first call, It works perfectly. I have googled it and did so many tries like setting timeouts but nothing worked. Any suggestions will be highly appreciated. Also, if more details are required please let me know, I will post the required code.
A MDI Child form will call this method.
Debugger shows CommunicationException.
Trace Viewer shows message: The operation cannot be completed because the pipe was closed. This may have been caused by the application on the other end of the pipe exiting.
Contract
[ServiceContract(Namespace = "http://Company/ManagementInformationSystemServices/", SessionMode = SessionMode.Required)]
public interface IPrincipalService
{
#region Service contracts for Reports
[OperationContract]
[FaultContract(typeof(ProcessExecutionFault))]
Parcel InsertParcel(Parcel singleParcel, out bool Exists);
[OperationContract]
[FaultContract(typeof(ProcessExecutionFault))]
Parcel GetByParcelId(int id);
#endregion
}
Contract Implementation
[ServiceBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
public class PrincipalService : IPrincipalService
{
#region Constructor
public PrincipalService()
{
}
#endregion
#region Public Methods
#region Parcel Methods
public Parcel InsertParcel(Parcel singleParcel, out bool Exists)
{
bool ExistsInner = false;
try
{
ParcelComponent parcelComponent = new ParcelComponent();
singleParcel = parcelComponent.Insert(singleParcel, out ExistsInner);
Exists = ExistsInner;
return singleParcel;
}
catch (Exception ex)
{
throw new FaultException<ProcessExecutionFault>
(new ProcessExecutionFault(LogResource.InsertParcelExistsError, ex), ex.Message);
}
}
public Parcel GetByParcelId(int id)
{
try
{
ParcelComponent parcelComponent = new ParcelComponent();
return parcelComponent.GetById(id);
}
catch (Exception ex)
{
throw new FaultException<ProcessExecutionFault>
(new ProcessExecutionFault(LogResource.ReadParcelError, ex), ex.Message);
}
}
#endregion
#endregion
}
Server Configuration
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<services>
<service behaviorConfiguration="serviceBehavior" name="ManagementInformationSystem.Services.PrincipalService">
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/ManagementInformationSystemServices" />
</baseAddresses>
</host>
<endpoint address="PrincipalService"
binding="netNamedPipeBinding"
contract="ManagementInformationSystem.Services.Contracts.IPrincipalService" />
<endpoint address="PrincipalService/mex"
binding="mexNamedPipeBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
</behaviors>
<diagnostics wmiProviderEnabled="true">
</diagnostics>
Client Configuration
<system.serviceModel>
<bindings>
<netNamedPipeBinding>
<binding name="NetNamedPipeBinding_IPrincipalService" />
</netNamedPipeBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="endpointBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="net.pipe://localhost/ManagementInformationSystemServices/PrincipalService"
binding="netNamedPipeBinding" bindingConfiguration="NetNamedPipeBinding_IPrincipalService"
contract="PrincipalServiceReference.IPrincipalService" name="NetNamedPipeBinding_IPrincipalService">
<identity>
<userPrincipalName value="company-238\company" />
</identity>
</endpoint>
</client>
<diagnostics wmiProviderEnabled="true">
</diagnostics>
Service Helper Class and I am getting Communication Exception here
public static class ServiceHelper<T>
{
public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>(GlobalResource.PrincipalServiceEndPointName);
public static void Use(UseServiceDelegate<T> codeBlock)
{
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
bool success = false;
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
}
catch (CommunicationException ex)
{
throw ex;
}
catch (TimeoutException ex)
{
throw ex;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
}

WCF Callback not calling back

I have read many articles here on SO, and on MSDN and Code Project. And still the answer eludes me.
I have created a WCF service that has a callback contract, and a Windows Forms app (test harness) that implements the callback interface.
Here are the interfaces:
[ServiceContract]
public interface ICacheService
{
[OperationContract]
bool AddToCache(string type, string key, string source, object item, int duration);
[OperationContract]
bool Remove(string key);
}
[ServiceContract(SessionMode=SessionMode.Required, CallbackContract=typeof(ISearchCallback))]
public interface ICacheSearch
{
[OperationContract(IsOneWay=true)]
void SearchCache(string source);
}
public interface ISearchCallback
{
[OperationContract(IsOneWay=true)]
void OnCallback(object data);
}
My service (left out the Add and Remove to conserve space - they work as expected):
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
public class CachingService : ICacheService, ICacheSearch, IDisposable
{
private List<ICache> _cacheList = new List<ICache>();
private ISearchCallback _callback = null;
public void SearchCache(string source)
{
try
{
_callback = OperationContext.Current.GetCallbackChannel<ISearchCallback>();
List<object> items = new List<object>();
foreach (ICache cache in this._cacheList)
{
foreach (CacheItem item in cache.GetCacheItemsBySource(source))
{
items.Add(item.Value);
}
}
ReadOnlyCollection<object> outList = new ReadOnlyCollection<object>(items);
_callback.OnCallback(outList);
}
catch { }
}
}
My service is hosted in a Windows Service. Here is the system.serviceModel section from app.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding
name="WSHttpBinding_ICacheService"
closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:01:00"
sendTimeout="00:01:00"
maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
</binding>
</wsHttpBinding>
<wsDualHttpBinding>
<binding
name="WSDualHttpBinding_ICacheSearch"
closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:01:00"
sendTimeout="00:01:00"
maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647"
clientBaseAddress="http://localhost:5057/wsDualHttpBinding"
useDefaultWebProxy="true"
transactionFlow="false">
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
</binding>
</wsDualHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="CacheService.CachingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:5055/CachingService/"/>
</baseAddresses>
</host>
<endpoint address="Search" binding="wsDualHttpBinding" contract="CacheService.ICacheSearch" />
<endpoint address="" binding="wsHttpBinding" contract="CacheService.ICacheService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<client>
<endpoint address="http://localhost:5055/CachingService/Search" binding="wsDualHttpBinding"
bindingConfiguration="WSDualHttpBinding_ICacheSearch" contract="CacheService.ICacheSearch"
name="WSDualHttpBinding_ICacheSearch" />
<endpoint address="http://localhost:5055/CachingService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_ICacheService" contract="CacheService.ICacheService"
name="WSHttpBinding_ICacheService" />
</client>
</system.serviceModel>
Finally, I created a simple Windows Forms app to test. It is declared as:
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Single)]
public partial class Form1 : Form, cacheService.ICacheSearchCallback
{
InstanceContext context = null;
cacheService.CacheServiceClient _service = null;
cacheService.CacheSearchClient _proxy = null;
private void Form1_Load(object sender, EventArgs e)
{
_syncContext = System.Threading.SynchronizationContext.Current;
_service = new cacheService.CacheServiceClient();
this.dataGridView1.AutoGenerateColumns = true;
context = new InstanceContext(this);
_proxy = new cacheService.CacheSearchClient(context);
RefreshList();
}
private void RefreshList()
{
_proxy.SearchCache("mySource");
}
public void OnCallback(object data)
{
this._data = data;
this.dataGridView1.DataSource = this._data;
}
The call to the service (_proxy.SearchCache("mySource")) successfully executes the method on the service and service calls _callback.OnCallback(outList). But the callback method implemented in my test app is never called and so the data are never conveyed to the test app.
Again, I have looked at every recent WCF article on SO and many other blogs and code sites. I feel like I need a another pair of eyes to point out the obvious so I can get back to work.
Many thanks,
Robert

WCF service will not return 500 Internal Server Error. Instead, only 400 Bad Request

I've created a simple RESTful WCF file streaming service. When an error occurs, I would like a 500 Interal Server Error response code to be generated. Instead, only 400 Bad Requests are generated.
When the request is valid, I get the proper response (200 OK), but even if I throw an Exception I get a 400.
IFileService:
[ServiceContract]
public interface IFileService
{
[OperationContract]
[WebInvoke(Method = "GET",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/DownloadConfig")]
Stream Download();
}
FileService:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class GCConfigFileService : IGCConfigFileService
{
public Stream Download()
{
throw new Exception();
}
}
Web.Config
<location path="FileService.svc">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
<system.serviceModel>
<client />
<behaviors>
<serviceBehaviors>
<behavior name="FileServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="FileService"
behaviorConfiguration="FileServiceBehavior">
<endpoint address=""
binding="webHttpBinding"
bindingConfiguration="FileServiceBinding"
behaviorConfiguration="web"
contract="IFileService"></endpoint>
</service>
</services>
<bindings>
<webHttpBinding>
<binding
name="FileServiceBinding"
maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647"
transferMode="Streamed"
openTimeout="04:01:00"
receiveTimeout="04:10:00"
sendTimeout="04:01:00">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</binding>
</webHttpBinding>
</bindings>
SIMPLE:
Try out throw new WebFaultException(HttpStatusCode.InternalServerError);
To specify an error details:
throw new WebFaultException<string>("Custom Error Message!", HttpStatusCode.InternalServerError);
ADVANCED:
If you want better exception handling with defining HTTP status for each exception you'll need to create a custom ErrorHandler class for example:
class HttpErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return false;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (fault != null)
{
HttpResponseMessageProperty properties = new HttpResponseMessageProperty();
properties.StatusCode = HttpStatusCode.InternalServerError;
fault.Properties.Add(HttpResponseMessageProperty.Name, properties);
}
}
}
Then you need to create a service behaviour to attach to your service:
class ErrorBehaviorAttribute : Attribute, IServiceBehavior
{
Type errorHandlerType;
public ErrorBehaviorAttribute(Type errorHandlerType)
{
this.errorHandlerType = errorHandlerType;
}
public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
{
IErrorHandler errorHandler;
errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
channelDispatcher.ErrorHandlers.Add(errorHandler);
}
}
}
Attaching to behaviour:
[ServiceContract]
public interface IService
{
[OperationContract(Action = "*", ReplyAction = "*")]
Message Action(Message m);
}
[ErrorBehavior(typeof(HttpErrorHandler))]
public class Service : IService
{
public Message Action(Message m)
{
throw new FaultException("!");
}
}

Categories

Resources