Adding global error handling to WCF REST service - wcf

I have a WCF/REST Web Service that I'm trying to add a global exception handler to. I'm looking for something similar to the Application_Error event in a standard .NET website.
I've found lots of info about using IErrorHandler and IServiceBehavior like what's detailed here: http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.aspx#Y1479
That seems like what I need, but every example I've found assumes that the service is defined in the web.config. I'm not doing that - I'm using RouteTables, configured in the global.asax, like so:
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
// Edit the base address of Service1 by replacing the "Service1" string below
RouteTable.Routes.Add(new ServiceRoute("", new WebServiceHost2Factory(), typeof(myService)));
}
So, given that, how do I configure my custom IErrorHandler and IServiceBehavior? Am I even on the right track, given that I'm using a RouteTable rather than configuring it via the web.config? I'm very new to WCF....

The wiring up of your IServiceBehaviour can be achieved by creating a custom WebServiceHostFactory that overrides CreateServiceHost.
For example if you have a class GlobalErrorHandlerBehaviour which implements IServiceBehavior, then you could wire it up as follows:
public class CustomWebServiceHostFactory : WebServiceHostFactory
{
protected override ServiceHost CreateServiceHost(System.Type serviceType, System.Uri[] baseAddresses)
{
return ApplyGlobalErrorHandler(base.CreateServiceHost(serviceType, baseAddresses));
}
private ServiceHost ApplyGlobalErrorHandler(ServiceHost serviceHost)
{
serviceHost.Description.Behaviors.Add(new GlobalErrorHandlerBehaviour());
return serviceHost;
}
}
You would then update your call to the ServiceRoute constructor to pass in this custom factory.

Related

HttpContext.Current.Session is null when injecting it to interceptor / or using in inside interceptor (mvc4 webapi)

I have mvc4 WebAPI application with castle Windsor interception.
The interceptor class needs HttpContext.Current.Session.
When I call it directly from the interceptor, it is null.
So I read here that I need to inject the Session and not just access it in the interceptor.
This the code I ended up with...
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container.Kernel));
this.RegisterDependencyResolver();
this.container.Install(new WindsorWebApiInstaller());
}
public class WindsorWebApiInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// the following interceptor needs Session object
container.Register( Component.For<IInterceptor>()
.ImplementedBy<SecurityInterceptor>()
.LifestylePerWebRequest()
.Named("SecurityInterceptor"));
// session is null here, So Castle wont inject it and throw exception...
container.Register(
Component.For<HttpSessionStateBase>().UsingFactoryMethod(
() => new HttpSessionStateWrapper(HttpContext.Current.Session)).LifestylePerWebRequest());
}
}
Is there any other way to access the session from the interceptor?
Thanks
I always forget that WEBAPI is not MVC.
this is not castle issue.
this did the trick!
public override void Init()
{
this.PostAuthenticateRequest += MvcApplication_PostAuthenticateRequest;
base.Init();
}
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
System.Web.HttpContext.Current.SetSessionStateBehavior(
SessionStateBehavior.Required);
}
https://stackoverflow.com/a/15038669/936651
+1 to #Soren

NinjectServiceHost in WCF service does not call Dispose()

I've been trying to get the Dispose method on my IDisposable WCF service called whilst using Ninject's NinjectServiceHost without any luck. I've then downloaded the Ninject.extensions.WCF example code and tried to get the IDisposable TimeService's Dispose() method to be called, but it does not get called either.
The service is instantiated correctly, just the Dispose() doesn't get called.
Is this a bug or something that myself and the example code are missing?
I've created a stripped down service and testing host that reproduces the issue. The code is below.
I'm using Ninject 3.0.1.10, Ninject.extensions.WCF 3.0.0.5, .net 4.5
ServiceModule.cs code (for setting up bindings)
using Ninject.Modules;
namespace TestNinjectWcf
{
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<Service1>().ToSelf();
// I've also tried Bind<IService1>().To<Service1>()
// and also tried various scopes such as InParent() and InRequestScope()
}
}
}
Console Test Program to start the service.
using System;
using Ninject.Extensions.Wcf;
using Ninject;
using TestNinjectWcf;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel(new ServiceModule());
var service = kernel.Get<NinjectServiceHost<Service1>>();
service.Open();
Console.WriteLine("Service Started");
Console.ReadKey();
service.Close();
}
}
}
Service Implementation
using System;
using System.Diagnostics;
using System.ServiceModel;
namespace TestNinjectWcf
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1, IDisposable
{
public Service1()
{
Debug.WriteLine("Constructor");
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public void Dispose()
{
Debug.WriteLine("Dispose"); // This line never gets called!
}
}
}
Maybe it is that you have created singleton service ? (InstanceContextMode.Single)
Only one InstanceContext object is used for all incoming calls and is not recycled subsequent to the calls. If a service object does not exist, one is created

Ninject WCF extention with already existing ServiceHostFactory and ServiceHost

We have a difficulty to use Ninject wcf extensions. We host our services in IIS and using svc files. We have read a lot of posts describing usage of NinjectServiceHostFactory(in svc files) with NinjectHttpApplication (in global.asax file) and it seems very simple.
Our problem is that we already have our custom ServiceHostFactory and ServiceHost.
Can someone point us what is the right way combining our ServiceHostFactory with NinjectServiceHostFactory?
Our svc files point to the our custom ServiceHostFactory.
UPDATE
It seems that we managed to implement it.
Our ServiceHostFactory implementation:
public class CustomServiceHostFactory : NinjectServiceHostFactory
{
protected override Type ServiceHostType
{
get
{
return typeof(CustomServiceHost<>);
}
}
}
Our ServiceHost implementation:
public class CustomServiceHost<T> : NinjectAbstractServiceHost<T>
{
public CustomServiceHost(IServiceBehavior serviceBehavior, T serviceType, params Uri[] baseAddresses) : base(serviceBehavior, serviceType, baseAddresses)
{
...
}
protected override void OnOpening()
{
...
base.OnOpening();
}
}

In WCF how do I remove the 404 response body?

I have a WCF service configured and I'm using routing to configure it. Everything is working the way I want it, except the 404 messages have a body stating Service Endpoint not found.
I'd like the 404 to have an empty response body.
Here is my route registration:
public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private void RegisterRoutes(RouteCollection routes)
{
routes.Add(new ServiceRoute("RootService", new WebServiceHostFactory(), typeof(ServiceProvider)));
}
Here is my service class:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceContract]
public class ServiceProvider
{
[WebGet]
public Test ValidUrl()
{
return new Test();
}
}
How do I make the response for this url http://localhost/RootService have an empty 404 body?
I found a few ways to do this and I've listed two below. They key is having the UriTemplate set as *. This makes the method match all routes that aren't explicitly matched otherwise.
[WebGet(UriTemplate="*")]
public void ErrorForGet()
{
throw new WebFaultException(HttpStatusCode.NotFound);
}
I don't like this way as well, but it works:
[WebGet(UriTemplate="*")]
public void ErrorForGet()
{
WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound();
}
Both of these methods have overloads that take a string as a message to provide to the requesting client. The WebFaultException needs to be like this going that route though: throw new WebFaultException<string>("Resource not found", HttpStatusCode.NotFound);

WCF security via message headers

I'm trying to implement "some sort of" server-client & zero-config security for some WCF service.
The best (as well as easiest to me) solution that I found on www is the one described at http://www.dotnetjack.com/post/Automate-passing-valuable-information-in-WCF-headers.aspx (client-side) and http://www.dotnetjack.com/post/Processing-custom-WCF-header-values-at-server-side.aspx (corrisponding server-side).
Below is my implementation for RequestAuth (descibed in the first link above):
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Configuration;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
namespace AuthLibrary
{
/// <summary>
/// Ref: http://www.dotnetjack.com/post/Automate-passing-valuable-information-in-WCF-headers.aspx
/// </summary>
public class RequestAuth : BehaviorExtensionElement, IClientMessageInspector, IEndpointBehavior
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string headerName = "AuthKey";
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string headerNamespace = "http://some.url";
public override Type BehaviorType
{
get { return typeof(RequestAuth); }
}
protected override object CreateBehavior()
{
return new RequestAuth();
}
#region IClientMessageInspector Members
// Keeping in mind that I am SENDING something to the server,
// I only need to implement the BeforeSendRequest method
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
throw new NotImplementedException();
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
MessageHeader<string> header = new MessageHeader<string>();
header.Actor = "Anyone";
header.Content = "TopSecretKey";
//Creating an untyped header to add to the WCF context
MessageHeader unTypedHeader = header.GetUntypedHeader(headerName, headerNamespace);
//Add the header to the current request
request.Headers.Add(unTypedHeader);
return null;
}
#endregion
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
throw new NotImplementedException();
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(this);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
throw new NotImplementedException();
}
public void Validate(ServiceEndpoint endpoint)
{
throw new NotImplementedException();
}
#endregion
}
}
So first I put this code in my client WinForms application, but then I had problems signing it, because I had to sign also all third-party references eventhough http://msdn.microsoft.com/en-us/library/h4fa028b(v=VS.80).aspx at section "What Should Not Be Strong-Named" states:
In general, you should avoid strong-naming application EXE assemblies. A strongly named application or component cannot reference a weak-named component, so strong-naming an EXE prevents the EXE from referencing weak-named DLLs that are deployed with the application.
For this reason, the Visual Studio project system does not strong-name application EXEs. Instead, it strong-names the Application manifest, which internally points to the weak-named application EXE.
I expected VS to avoid this problem, but I had no luck there, it complained about all the unsigned references, so I created a separate "WCF Service Library" project inside my solution containing only code above and signed that one.
At this point entire solution compiled just okay.
And here's my problem:
When I fired up "WCF Service Configuration Editor" I was able to add new behavior element extension (say "AuthExtension"), but then when I tried to add that extension to my end point behavior it gives me:
Exception has been thrown by the target of an invocation.
So I'm stuck here.
Any ideas?
You have some:
throw new NotImplementedException();
in your code. These could be the exceptions that are being thrown. Try removing these and see if you get the same error.
Shiraz Bhaiji is right. The framework does call those methods that you are throwing not implemented exceptions. Remove that.