WCF security via message headers - wcf

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.

Related

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

Handling Invalid URI passed to a WCF service

I have WebGet, and WebInvoke attributes describing my contract, but what is the best method of handling invalid URI's? Right now, if a user passes an URI that does not match my current operations, they get an "Endpoint not found." message. I want to pass back a more descriptive message.
For example, my URI template looks like:
/Stuff/{ID}/subStuff
but say they type
/Stuff/{ID}/OtherStuff
There is no such thing as OtherStuff, and I do not have a template for that.
Is there a way to cover all non mapped URI's with a single contract?
Thanks!
If you want to catch all the unhandled requests at a global level in WCF REST then you have to create a custom WebHttpBehavior and custom IOperationInvoker as described in this post.
If you want to return a custom error text with custom status code(404) you can also look into the WebOperationContext.OutgoingResponse property as described here.
While I did follow the links mark provided, and they did give a hint of what I needed. The answers that were linked did not actually answer my original question.
I was able to follow the steps, and I wanted to list my steps to solve this problem on this question as well.
To create my own response to any URI that was not mapped to a method in my contract I created the following:
A custom ServiceHostFactory
Behavior that I mapped to my end points within the custom ServiceHostFactory
a dispatcher that would handle all unmapped uri's that were provided to the service.
Below are the full definitions of the object's I created:
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace your.namespace.here
{
public class CustomServiceHostFactory : WebServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
ServiceHost host = base.CreateServiceHost(serviceType, baseAddresses);
//note: these endpoints will not exist yet, if you are relying on the svc system to generate your endpoints for you
// calling host.AddDefaultEndpoints provides you the endpoints you need to add the behavior we need.
var endpoints = host.AddDefaultEndpoints();
foreach (var endpoint in endpoints)
{
endpoint.Behaviors.Add(new WcfUnkownUriBehavior());
}
return host;
}
}
}
As you can see above, we are adding a new behavior: WcfUnknownUriBehavior. This new custom behavior's soul duty is to replace the UnknownDispatcher. below is that implementation:
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
namespace your.namespace.here
{
public class UnknownUriDispatcher : IOperationInvoker
{
public object[] AllocateInputs()
{
//no inputs are really going to come in,
//but we want to provide an array anyways
return new object[1];
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
var responeObject = new YourResponseObject()
{
Message = "Invalid Uri",
Code = "Error",
};
Message result = Message.CreateMessage(MessageVersion.None, null, responeObject);
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
outputs = new object[1]{responeObject};
return result;
}
public System.IAsyncResult InvokeBegin(object instance, object[] inputs, System.AsyncCallback callback, object state)
{
throw new System.NotImplementedException();
}
public object InvokeEnd(object instance, out object[] outputs, System.IAsyncResult result)
{
throw new System.NotImplementedException();
}
public bool IsSynchronous
{
get { return true; }
}
}
}
Once you have these objects specified, you can now use the new factory within your svc's "markup":
<%# ServiceHost Language="C#" Debug="true" Service="your.service.namespace.here" CodeBehind="myservice.svc.cs"
Factory="your.namespace.here.CustomServiceHostFactory" %>
And that should be it. as long as your object "YourResponseObject" can be serialized, it's serialized representation will be sent back to the client.

How do I program my WCF service in the given scenario?

I am currently developing a C# Windows Form Application that I intend to let it interact with a server. The server will receive posting from a mobile application that I have developed and whenever a posting is received, my Windows Form Application should be notified and give me a notification.
E.g. My mobile application sends an message over to my server. Once my server receives the message, my windows form application should display a new notification showing the content of the message received.
I am now starting to develop the WCF service and has reach the PostingService method and I am unsure of how I am able to continue to program the service to work the way I wan as stated above.
public class PostingService : IPostingService
{
public void NotifyAboutPosting(Posting post)
{
// do something with post here
}
}
and after I program the service, how do I test the service by, I dunno? uploading a fake post to see if the services works or whatsoever , meaning a dummy test. thanks !
EDIT
for my main method, the code are as follows ,
Uri baseAddress = new Uri("http://localhost/");
ServiceHost selfHost = new ServiceHost(typeof(IPostingService), baseAddress);
try
{
selfHost.AddServiceEndpoint(typeof(IPostingService),new WSHttpBinding(), "Posting");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
selfHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("An exception occurred: {0}", ce.Message);
selfHost.Abort();
}
basically I just followed through the tutorial given by MSDN WCF getting started tutorial. not sure if this is really the correct way to do it for the type of implementation that I want.
Well, your WCF service can do anything you want - so what do you really want it to do??
Your posting server gets a new message from a mobile device, and then calls this WCF service class in your Winforms app. What do you want to happen here and now??
One thing to keep in mind: the WCF service class receiving the message and the Winforms app might be running on different threads; if that's the case, you cannot just update e.g. UI elements on your Winforms UI from the service code (you need to use some synchronization methods). But that depends on your exact way of creating and opening the ServiceHost in your Winforms app.
Update: if you put your code to create and initialize your ServiceHost into the main application form (see Service Synchronization Context on CodeIdol for a sample on how to do this), then you could probably just do:
public class PostingService : IPostingService
{
public void NotifyAboutPosting(Posting post)
{
MessageBox.Show(post.Title, post.Message,
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
assuming your Posting class has both a .Title and a .Message string property...
1) PostingService assembly (class-library project)
Interface: IPostingService.cs
using System;
using System.ServiceModel;
namespace PostingService
{
[ServiceContract]
public interface IPostingService
{
[OperationContract]
void NotifyAboutPosting(Posting posting);
}
}
Implementation: PostingService.cs
using System;
using System.Windows.Forms;
namespace PostingService
{
public class PostingService : IPostingService
{
public void NotifyAboutPosting(Posting posting)
{
MessageBox.Show(posting.Message, posting.Title, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
DataContract: Posting.cs
using System;
using System.Runtime.Serialization;
namespace PostingService
{
[DataContract]
public class Posting
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string Message { get; set; }
}
}
2) Your Winforms app (Winforms application project)
Must reference the service assembly (since it needs the service contract and the data contract class)
Main Form of your app: Form1.cs
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Windows.Forms;
using PostingService; // your class library from above
namespace WinformsApp
{
public partial class Form1 : Form
{
private ServiceHost _host = null;
public Form1()
{
InitializeComponent();
// IMPORTANT: here you need the **SERVICE IMPLEMENTATION CLASS** in the typeof() (*NOT* the interface!)
_host = new ServiceHost(typeof(PostingService), new Uri("http://localhost:8888/PostingService"));
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
_host.Description.Behaviors.Add(smb);
_host.Open();
label2.Text = "Service up and running (http://localhost:8888/PostingService)";
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
_host.Close();
base.OnFormClosed(e);
}
}
}
3) Run your Winforms app - now that service is up and running and ready to be notified.
4) Launch WCF Test Client (that's what your "posting server" will be doing later on)
4a) File > Add Service - type in http://localhost:8888/PostingService - should find your service
4b) if found: enter some values into the properties for the "Posting" class (an ID, title, message)
4c) Click "Invoke" - your service should now be called, a dialog pop (message box) should pop up with the title and message you've defined
Perhaps WCF callbacks might meet your requirements:
What You Need To Know About One-Way Calls, Callbacks, And Events

Adding global error handling to WCF REST service

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.

WCF Rest Error Handling

I'm having a mind blowing problem using WCF 4.0 RESTful service. I am trying to make a rest service that will return, in case of an error, a xml document describing the problem
ex :
<ErrorHandler>
<cause>Resource not available</cause>
<errorCode>111103</errorCode>
</ErrorHandler>
In order to make this i've created a default REST service using the template provided by visual studio
Here is my service Class :
public class Service1
{
// TODO: Implement the collection resource that will contain the SampleItem instances
[WebGet(UriTemplate = "")]
public List<SampleItem> GetCollection()
{
// TODO: Replace the current implementation to return a collection of SampleItem instances\
// throw new WebException("lala");
throw new WebFaultException<ErrorHandler>(new ErrorHandler { cause = "Resource not available", errorCode = 100 }, System.Net.HttpStatusCode.NotFound);
//return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = "Hello" } };
}
[WebInvoke(UriTemplate = "", Method = "POST")]
public SampleItem Create(SampleItem instance)
{
// TODO: Add the new instance of SampleItem to the collection
return new SampleItem() { Id = 3, StringValue = "59" };
}
[WebGet(UriTemplate = "{id}")]
public SampleItem Get(string id)
{
// TODO: Return the instance of SampleItem with the given id
throw new NotImplementedException();
}
[WebInvoke(UriTemplate = "{id}", Method = "PUT")]
public SampleItem Update(string id, SampleItem instance)
{
// TODO: Update the given instance of SampleItem in the collection
throw new NotImplementedException();
}
[WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
public void Delete(string id)
{
// TODO: Remove the instance of SampleItem with the given id from the collection
throw new NotImplementedException();
}
}
}
As you can see from the code above i am throwing a WebFaultException in the GetCollection method. that should put in the body of the response a "ErrorHandler" object.
Here is how my ErrorHandler class looks like :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
namespace WcfRestService1
{
[DataContract]
public class ErrorHandler
{
[DataMember]
public int errorCode { get; set; }
[DataMember]
public string cause { get; set; }
}
}
The crazy thing is that this thing works but it down't :)). What i'm trying to say is that visual studio is giving me an error saying that the WebFaultException is not caught by the user code :| and it suspends my app. If i press continue everything works as it should.
Here are some pictures describing my problem:
First step in fiddler :
First Step
Next Visual Studio's error: Visual Studio Error
Finally After pressing continue everything works :
It makes no sense to me and i have no idea why this thing is happening and how to fix it :P. I've searched the web for days trying to find a solution with no luck. I'm using Visual Studio 2010 Ultimate
Best Regards :)
Nothing is wrong here. You are debugging, an exception is thrown, it breaks, you continue and it works as it should.
I suspect you have set the exception handling option (Ctrl+Alt+E) to break when exceptions are thrown. ("Thrown" in the options) This will cause break whenever exception is thrown regardless it is handled.
Exceptions that are thrown in WCF operations will be handled by the WCF runtime and if they are faults, they will be sent back as such so that channel is not faulted.
Now with regard to sending back an XML, you can just send string representation of the XML using WebFaultException<string>.