Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF Parameter Validation with Interceptor

I have a WCF service with operations that all require MyServiceRequest parameter (or derived type) and returns MyServiceResponse (or dervived type), i.e.:

    [OperationContract]
    MySeviceResponse FindAppointments(FindAppointmentRequest request);

    [OperationContract]
    MyServiceResponse MakeAnAppointment(MakeAnAppointmentRequest request);

    [OperationContract]
    MyServiceResponse RegisterResource(RegisterResourceRequest request);

FindAppointmentRequest, MakeAnAppointmentRequest and RegisterResourceRequest extends MyServiceRequest which contains properties UserName and UserPassword.

None of this method executes properly should there be wrong UserName/UserPassword pair in Request.

I want to create an interceptor which not only checks if given UserName/UserPassword pair is correct (which is pretty simple with IParameterInspector) but also returns to the client object of type ErrorRespone that extends MyServiceResponse.

Can IParameterInspector prevent service from executing requested method and return ErrorResponse strightaway?

like image 387
mgamer Avatar asked Nov 28 '09 10:11

mgamer


1 Answers

IParameterInspector can prevent operation from executing by throwing an exception. Here's an example.

Define a custom fault contract:

public class DataAccessFaultContract
{
    public string ErrorMessage { get; set; }
}

Then the inspector:

public class InspectorAttribute : Attribute, IParameterInspector, IOperationBehavior
{
    public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
    {

    }

    public object BeforeCall(string operationName, object[] inputs)
    {
        MyServiceRequest request = null;
        if (inputs != null && inputs.Length > 0)
        {
            request = inputs[0] as MyServiceRequest;
        }

        if (request != null && request.Username != "user" && request.Password != "secret")
        {
            var fc = new DataAccessFaultContract{ ErrorMessage = "Invalid user" };
            throw new FaultException<DataAccessFaultContract>(fc);
        }
        return null;
    }

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.ParameterInspectors.Add(this);
    }

    public void Validate(OperationDescription operationDescription)
    {
    }
}

And finally decorate your operation with appropriate attributes:

[ServiceContract]
public interface IMyServiceContract
{
    [Inspector]
    [FaultContract(typeof(DataAccessFaultContract))]
    [OperationContract]
    MySeviceResponse FindAppointments(FindAppointmentRequest request);

    ...
}

When invoking the service, the client could check for FaultException:

try
{
    var response = client.FindAppointments(request);
}
catch (FaultException<DataAccessFaultContract> ex)
{
    string errorMessage = ex.Detail.ErrorMessage;
    // ...
}
like image 145
Darin Dimitrov Avatar answered Oct 21 '22 02:10

Darin Dimitrov