Hosting

Topics: Web Api
Oct 31, 2010 at 10:23 PM

Apparently, the first preview can only be hosted on ASP.NET (WebHttpServiceHost forces AspNetCompatibilityRequirementsAttribute to Required).

 1) Is that by design?

 2) Is it going to change in future versions?

 3) What is the dependency on ASP.NET that forces this requirement?

Thanks

Regards

Pedro Felix

Oct 31, 2010 at 10:33 PM

I don't have the bits yet - have to repave a new laptop tomorrow. But I'm watching Glenn's talk from PDC. Let me state my assumptions (which may be completely erroneous): I have to host in ASP.NET (not WAS but ASP.NET Compat) and I have to use XmlSerializer (Glenn mentioned its POX including attributes for XML). Why would you build this on WCF and not ASMX or ASP.NET MVC? I don't really see what WCF is buying you here.

I'd love to hear what I'm missing as it may be an issue of not using the bits yet

Rich

Coordinator
Oct 31, 2010 at 11:15 PM

No those assumptions are not correct :-)

You don't have to host on ASP.NET, you CAN host on ASP.NET and integrate with routes etc. We do support self-host / on top of IIS.

You do not HAVE to use the XmlSerializer. In WCF today you end up getting the DataContractSerializer by default which doesn't give you all the flexibility of the Xml serializer i.e. it doesn't support Xml attributes (meaning only elements). The point here is that we're allowing you to use the XmlSerializer out of the box. That is just one of many media types supported. If you watch my talk you can plug in whatever formats you want. More on this to come.

If MVC works for you, then you can definitely use it. I would check out Darrel Miller's blog post though which gives some more insights into what is different about the work we are doing as it compares to ASP.NET, WCF Data Services, etc.

Thanks

Glenn

Coordinator
Oct 31, 2010 at 11:20 PM

 

If you use WebHttpServiceHost directly you can self-host. Hosting on top of IIS may not currently be supported, but it will be.

Oct 31, 2010 at 11:24 PM

Hi, 

Thanks for the reply.

What do you mean by "self-host / on top of IIS". I'm unable to self-host on a console app. I get the following exception:

  "Unhandled Exception: System.InvalidOperationException: This service requires ASP.NET compatibility and must be hoste IIS.  Either host the service in IIS with ASP.NET compatibility turned   on in web.config or set the AspNetCompatibilequirementsAttribute.AspNetCompatibilityRequirementsMode property to a value other than Required."

I've looked into the WebHttpServiceHost source and observed that it always forces AspNetCompatibilityRequirementsAttribute to Required.

Thanks

Pedro

 

Nov 1, 2010 at 12:20 AM

Thanks Glenn - thats a relief

Re XmlSerializer - WCF has always allowed you to use XmlSerializer out of the box - the phrasing of the talk (unless there is more to come on this) seemed to imply by "you can use attributes" that DataContractSerializer was not in scope, only XmlSerializer. And ofc we have always been able to return any data format in the WCF REST support using Stream as a return type and just setting the content type to what we want

 

 

Coordinator
Nov 1, 2010 at 12:30 AM

Richard yes you could always return a stream, but then you would only support stream. With this model you can return an object and then have the correct format applied based on content negotation.

On the question of DataContractSerializer, our default thinking was to not use it for XML. Do you think that's necessary?

Coordinator
Nov 1, 2010 at 12:33 AM

@pmhsfelix the service host / service host factory code is a prototype. You are are correct though it appears that it is forcing it. The reasoning for that was to avoid requiring annotation on the service itself. The real one which will come soon will support both. For now you will probably have to make a small tweak to the code or use a custom one.

Thanks

Nov 1, 2010 at 12:41 AM

Richard,

When you get the source, dig into Microsoft.ServiceModel.Http.XmlProcessor.  You can see in there that it is currently using the XmlSerializer.  However, this code is just the default behaviour of the WebHttp prototype.  If you add the line: 

processors.ClearMediaTypeProcessors();

to the RegisterResponseProcessorsForOperation override, it will remove the XmlProcessor and you can replace it with something that outputs the content however you want.

Darrel

Coordinator
Nov 1, 2010 at 12:43 AM

Richard

For example if you want your service to support Xml, Json and Atom then using a stream means that you have to handle all that logic yourself. Take a look at the ContactResource which handles Xml and Json though the resource (service) itself has no knowledge of that i.e. it is a separate concern.

Nov 1, 2010 at 1:04 AM

Hi Glenn,

Thanks for the reply.

I've commented out the line that forces AspNetCompatibilityRequirementsAttribute to Required and done some more tests. I'm now able to self-host on a console app. However, I've found the following additional issues:

1) When requesting an unhandled URL (no UriTemplate match), I get a 500 error and not a 404 (Not Found) error.

2) When explicitly adding a new endpoint to a WebHttpServiceHost instance, I get the following exception

  "Unhandled Exception: System.InvalidOperationException: The Service contains multiple ServiceEndpoints with different ContractDescriptions which each have Name='TheService' and Namespace='http://tempuri.org/'.  Either provide ContractDescriptions with unique Name and Namespaces, or ensure the ServiceEndpoints have the same ContractDescription instance."

Apparently, this happens because of the way WebHttpServiceHost creates the service description and the service endpoint - directly creates a ServiceEndpoint instead of using addServiceEndpoint.

3) The class HttpMessageEncodingBindingElement is internal, so I cannot use it to create a custom binding. I was trying to expose the service via the AppFabric's service bus.

4) I'm using the following test code

[WebGet(UriTemplate="hello")]        

string Get(HttpRequestMessage req, HttpResponseMessage resp){

            resp.StatusCode = HttpStatusCode.OK;

            resp.Content = HttpContent.Create("hello web 2");

            return "hello web";        

}

I've got two different results using two-different user-agents

user-agent 1 - Chrome

Request

     Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5  

Response

     No content type

     Raw content: hello web 2


user-agent 2 - IE9

Request

    Accept: text/html, application/xhtml+xml, */*

Response

    Content-Type: text/xml

    Raw content: <?xml version="1.0"?> <string>hello web</string>

 

1) Looking into the two Accept headers, I cannot find a reason to the different response, however my media-type knowledge is minimum.

2) This type of code (two returns, one explicit and another implicit via HttpResponseMessage) can be misleading. I've saw something similar on the ContactManager sample.

 

Thanks

Pedro

 

Nov 1, 2010 at 1:52 AM

1)  I'm seeing the same behaviour. That may be broken because we have self hosted.   I'

m guessing IIS/Casini would have handled that before.  The previous self-hosted model used to return a 404.  I'm sure this will be fixed soon.

2)  By "explicitly" do you mean in code?  The current prototype assumes that you are going to add endpoints using the WebGet, WebInvoke attributes on a specific service.  Yeah it sucks, but don't worry we are not going to be limited to this model.  From what I can tell this prototype was intended to demonstrate two things, backward compatibility with System.ServiceModel.Web and the Processors.  Previous prototypes have been more flexible in the way you can setup endpoints.  Until we can find a way of cloning Glenn, we either have to be patient, or write a new HttpEndpointBehaviour class ourselves :-)

3) You're out of my league with that one.

4)  Strange, I'm not getting the same behaviour.  Whatever accept header I use, I'm always getting <?xml version="1.0"?> <string>hello web</string>

It seems like your XmlProcessor is not processing the return value from your operation and therefore the response you are getting is the one you are setting directly on the response object in the operation.

Coordinator
Nov 1, 2010 at 2:01 AM

I. That sounds like a bug. It will be fixed.

2. In the current drop only a single endpoint per host is supported. Can you give more info on what you are trying to do?

3. OK thanks, we will look into this.

4.1. Interesting. The second response is what would be expected. I will check it out.

4.2.  If you are returning a result from your operation, then you should not set the content on the HttpResponseMessage as conneg will take the result and set the response content. The main reason for pulling in the response in these cases is to set headers or to set the status code. In our final bits we will probably throw an exception if you try to set the content and have a return value.

In other words, for the example above the code should be the following:

[WebGet(UriTemplate="hello")]        
public string Get(HttpRequestMessage req, HttpResponseMessage resp){
  resp.StatusCode = HttpStatusCode.OK;
  return "hello web";        
}
 

Thanks

Glenn

 

 

Coordinator
Nov 1, 2010 at 2:03 AM

 

Adding to what Darrel said. We have a resource / convention based model which is non-attributed which we have also been prototyping. There wasn't time to get it out there "yet", but it will be out there in the next few drops.

Coordinator
Nov 1, 2010 at 2:05 AM

"The class HttpMessageEncodingBindingElement is internal, so I cannot use it to create a custom binding. I was trying to expose the service via the AppFabric's service bus."

Please go add a workitem :-)

Nov 1, 2010 at 3:32 PM

Hi all.

Thanks for all the replies.

Regarding the previous questions/issues,

2) I'm trying to explicitly add a new endpoint to a WebHttpServiceHost instance, by calling addServiceEndpoint. Regarding Glenn's statement's "In the current drop only a single endpoint per host is supported", I've seen that WebHttpServiceHost creates one endpoint for each base address.

My final goal here is to expose a WCF HTTP service on the AppFabric's Service Bus. For that, I need two things:

a) Create a custom binding using thw WCF HTTP encoder binding element and the service bus transport binding element

b) Explicitly add a new endpoint, for the same service contract, using the above custom binding.

 

4) Any findings regarding this behavior?

Once again, thanks.

Regards

Pedro

Coordinator
Nov 1, 2010 at 5:01 PM

Sorry that is correct, it is per base address.

Nov 13, 2010 at 9:44 PM

I don’t have anything to add other than I too am trying "to expose a WCF HTTP service on the AppFabric's Service Bus".

Pedro looks like he is way ahead of me, so I'm admitting that I’m standing on his coat tails and learning!. An example app with this configuration would be appreciated!

Regards,

Richard