Get Service Method Info

Topics: Web Api
Feb 19, 2011 at 1:29 PM

Hi,

I need to know what method will be executed in  a service call. My permissions will be based per method call, but I don't want to use permission code on every method of my services. I will decorate them with attributes and want to intercept the call to verify it in a centralized way.

Specializing HttpHostConfiguration with a DefaultHostConfiguration.GetInstance gives me service info but no method info.

Any suggestions or any info about future releases allowing this kind of thing?

 

Thank you

Feb 20, 2011 at 3:10 AM

Hi,

I am not sure how exactly you plan to do this, if you were thinking about a Processor you can check out the HttpOperationDescription class. There you have an "Attributes" property to retrieve the attributes of the method.

Cheers!

Gustavo

Feb 20, 2011 at 4:46 AM

Hi Gustavo,

I never though about using processors but I tested it like you suggested. It didn't work because HttpOperationDescription is available only on constructors of processors. They run on  initialization but not on further calls.

I could use aspects but I don't like the idea for this context. Intercepting is a much better option in my opinion.

If you have any other idea, please tell me. :)

Thank you,

Cassio

Coordinator
Feb 20, 2011 at 7:37 AM
The execute method runs on every call. A processor instance is created per operation. Thus you can grab the method info off of the HttpOperationDescription and use it to determine if the caller has access.

Sent from my Windows Phone

From: cassio_tavares
Sent: Saturday, February 19, 2011 11:46 PM
To: Glenn Block
Subject: Re: Get Service Method Info [wcf:246729]

From: cassio_tavares

Hi Gustavo,

I never though about using processors but I tested it like you suggested. It didn't work because HttpOperationDescription is available only on constructors of processors. They run on initialization but not on further calls.

I could use aspects but I don't like the idea for this context. Intercepting is a much better option in my opinion.

If you have any other idea, please tell me. :)

Thank you,

Cassio

Feb 20, 2011 at 1:56 PM

The solution was just in my face. Almost embarrassed because of that. :)

It worked. Now I will apply my permission control and try to abort the call if necessary.

Thank you both

Feb 20, 2011 at 3:00 PM

Hi again.

Now I don't know how to abort the pipeline execution.

I've tried to call CompleteRequest method from Global but it didn't worked.

Then I tried to throw an exception but it is swallowed by a method on Processor class.

I see that it returns the exception to my processor when I override OnError, but I don't know what to do.

 

Need help again.

Thank you

Coordinator
Feb 20, 2011 at 3:54 PM
On the Processor take HttpResponseMessage as one of the generic inputs. Name the param on execute HttpResponseMessage. Then modify the response and it should get returned.



Sent from my Windows Phone

From: cassio_tavares
Sent: Sunday, February 20, 2011 10:00 AM
To: Glenn Block
Subject: Re: Get Service Method Info [wcf:246729]

From: cassio_tavares

Hi again.

Now I don't know how to abort the pipeline execution.

I've tried to call CompleteRequest method from Global but it didn't worked.

Then I tried to throw an exception but it is swallowed by a method on Processor class.

I see that it returns the exception to my processor when I override OnError, but I don't know what to do.

Need help again.

Thank you

Feb 20, 2011 at 4:51 PM

It works but it process the whole operation (Business -> DB Access -> ...) before I can get the HttpResponseMessage from input.

I don't want/need to add this processor on response processors. The best option is to abort the request and return the response.

Do you agree?

Thanks.

Coordinator
Feb 20, 2011 at 5:18 PM

Yes

Put this in the request processors. You can still access the response. Currently aborting the pipeline is a bit ugly, but it will get cleaner in the next few weeks. Try getting the response message in the processor, setting it and then throwing an exception. Alternatively you can try creating an exception and returning it in the Error property on the result.

Glenn

 

 

Feb 21, 2011 at 5:04 AM

I really don't know how to get the response using only the request processor.

The input argument of the method OnExecute only has one item of type HttpRequestMessage.

And every exception that I throw inside the processor is swallowed.

Can you explain a little more?

Thanks, 

Cassio

Coordinator
Feb 21, 2011 at 6:21 AM
Processor is a generic class. If you derive from Processor<HttpResponseMessage, object> you will end up with an Execute method that has a param of type HttpResponseMessage. Rename the param on the method to HttpResponseMessage and the execute will have access to the response.

Sent from my Windows Phone

From: cassio_tavares
Sent: Monday, February 21, 2011 12:04 AM
To: Glenn Block
Subject: Re: Get Service Method Info [wcf:246729]

From: cassio_tavares

I really don't know how to get the response using only the request processor.

The input argument of the method OnExecute only has one item of type HttpRequestMessage.

And every exception that I throw inside the processor is swallowed.

Can you explain a little more?

Thanks,

Cassio

Feb 24, 2011 at 12:55 AM

Hi Glenn, me again

I've created a derived class from Processor<HttpResponseMessage, object> but what should I do now? I've tried to put it in the request processor pipeline but it doesn't work.

"Rename the param on the method to HttpResponseMessage and the execute will have access to the response"

And what do you mean by renaming? The param on method OnExecute is already of type HttpResponseMessage.

 

Thanks,

Cassio

Coordinator
Feb 24, 2011 at 1:01 AM
The name of the param on the method. The type is not enough as the match is on key and type. We use the param name as the key.

Sent from my Windows Phone

From: cassio_tavares
Sent: Wednesday, February 23, 2011 7:55 PM
To: Glenn Block
Subject: Re: Get Service Method Info [wcf:246729]

From: cassio_tavares

Hi Glenn, me again

I've created a derived class from Processor<HttpResponseMessage, object> but what should I do now? I've tried to put it in the request processor pipeline but it doesn't work.

"Rename the param on the method to HttpResponseMessage and the execute will have access to the response"

And what do you mean by renaming? The param on method OnExecute is already of type HttpResponseMessage.

Thanks,

Cassio

Feb 24, 2011 at 2:56 AM
Edited Feb 24, 2011 at 2:56 AM

It worked but the request is executing normally

What happened now:

HttpResponseMessage.Content = new StringContent("Test");
HttpResponseMessage.StatusCode = System.Net.HttpStatusCode.Unauthorized;
var result =  new System.ServiceModel.Dispatcher.ProcessorResult<object>();
result.Status = System.ServiceModel.Dispatcher.ProcessorStatus.Error;
result.Error = new UnauthorizedAccessException();  
result.Output = HttpResponseMessage;

The service method is called and the result is correct, but still not breaking the request.

if I throw an exception, like:
throw new UnauthorizedAccessException();
-The exception is swallowed
-result receives a new instance
-result.Output becomes null in the new instance
-Method protected override void DeserializeRequest(HttpRequestMessage message, object[] parameters) from HttpPipelineFormatter is executed
-Throws NullRefereceException on this code because result.Output is null:
	
var result = this.requestPipeline.Execute(GetRequestInArgumentValues(message, httpMessageProperty.Response).ToArray());
            for (int i = 0; i < parameters.Length; i++)
            {
                parameters[i] = result.Output[i];
            }

Am I doing something wrong?

Thanks
Coordinator
Feb 24, 2011 at 4:30 AM

Hi Cassio

I just verified that this is indeed a bug and it won't work in the current bits. It will be fixed for the next drop which should be next week.

Thanks

Glenn

Apr 18, 2011 at 11:47 PM

Is this still the correct way to handle this type of functionality?  I also need to verify a key/user authorization string on every request and need to be able to query an attribute on the target method for each request in order to determine if the method requires authorization.  I've created a processor that works as described above and was waiting on the next release to fix the bug.  Is this fixed?  Is a processor still the correct implementation?

Thanks,
David

Coordinator
Apr 19, 2011 at 12:03 AM

It sounds like an HttpOperationHandler will be the best way to do this in the current stack. One thing that has gotten easier is you no longer need to worry about the parameter name, just use any param of HttpRequestMessage in the handler.

Glenn

Apr 19, 2011 at 12:14 AM

Any samples or docs exist of creating/using a custom HttpOperationHandler?

Thanks,
David

Coordinator
Apr 19, 2011 at 12:52 AM

In the previous drops there were, I think in this drop everything has been ported either message handlers or our new formatters.

Here's an example though of how you could do it which I just whipped up. (Not tested)

    public class AuthorizationHandler : HttpOperationHandler<HttpRequestMessage, object>
    {
        private HttpOperationDescription _description; //used for accessing the handling method.

        public AuthorizationHandler(HttpOperationDescription description)
            :base("dummy") //return value is ignored here
        {
            _description = description;
        }

        public override object OnHandle(HttpRequestMessage req)
        {
            if (!IsValid(req))
            {
                var response = new HttpResponseMessage();
                response.StatusCode = HttpStatusCode.BadRequest;
                response.Content = new StringContent("Request is invalid", Encoding.UTF8, "text/plain");
                throw new HttpResponseException(response);
            }
            return null;
        }

        public bool IsValid(HttpRequestMessage req)
        {
           //put validation logic here
        }
    }

 To register you will need to create an OperationHandlerFactory which you will then set by calling SetOperationHandlerFactory on the config class. Ideally you would have been able to use the AddRequestHandlers method however it doesn't pass the operation description in the delegate which you use to add handlers. I will fix this though for the next drop so that you will be able to use that method.

Thanks

Glenn

Apr 19, 2011 at 1:02 AM

Wow Glenn!  Thanks for the sample.  I'll give it a shot.

-- David

Coordinator
Apr 19, 2011 at 11:18 AM

David

I just committed a change to our source tree (in the experimental branch / post preview 4) that will help with registration of the auth handler and without requiring a factory. If you grab the code in that branch, I have changed the AddRequestHandlers/AddResponseHandlers method to pass in the operation, this way you can now use an inline lambda syntax.

var builder = HttpHostConfiguration.Build().
  AddRequestHandlers((h,o)=>h.Add(new AuthorizationHandler(o));

Let me know if it works for you.

Apr 19, 2011 at 7:46 PM

Glenn,

That sample and those changes worked great!  It does exactly what I need.  I'm still working through some other migration issues, but for this I get called for each request with a list of method attributes for the target method and everything is just awesome-sauce after that.  Thanks again!

-- David