Why does the WCF 3.5 REST Starter Kit do this? - c#

I am setting up a REST endpoint that looks like the following:
[WebInvoke(Method = "POST", UriTemplate = "?format=json", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
and
[WebInvoke(Method = "DELETE", UriTemplate = "?token={token}&format=json", ResponseFormat = WebMessageFormat.Json)]
The above throws the following error:
UriTemplateTable does not support '?format=json' and '?token={token}&format=json' since they are not equivalent, but cannot be disambiguated because they have equivalent paths and the same common literal values for the query string. See the documentation for UriTemplateTable for more detail.
I am not an expert at WCF, but I would imagine that it should map first by the HTTP Method and then by the URI Template. It appears to be backwards. If both of my URI templates are:
?token={token}&format=json
This works because they are equivalent and it then appears to look at the HTTP Method where one is POST and the other is DELETE.
Is REST supposed to work this way? Why are the URI Template Tables not being sorted first by HTTP Method and then by URI Template? This can cause some serious frustrations when 1 HTTP Method requires a parameter and another does not, or if I want to do optional parameters (e.g. if the 'format' parameter is not passed, default to XML).

I believe this is simply a limitation of the routing capability of the UriTemplateTable. This is not a REST issue, just a WCF one I'm afraid.
Have you tried replicating the error in .Net 4.0? They seem to have done quite a bit of work to further support REST scenarios in .Net 4.

To fix this I had to do the following with my POST method:
[WebInvoke(Method = "POST", UriTemplate = "?token={token}&format=json", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json)]
My method declaration then took in an additional parameter called 'string token'. I then just ignore the value of 'token' in my method. If the client does not pass a value for token, WCF passes a null string, but since I am not working with it, it did not matter.
This is still frustrating with WCF 3.5, but it is a good workaround if anyone else runs into this.

Related

REST vs SOAP WCF Service - is there a downside for using both

When developing my WCF Service I originally planned using REST but later found out it will be called using SOAP. I have decorate my methods with both SOAP OperationalContract and REST WebInvoke but created only SOAP endpoint.
public interface IMyService
{
[OperationContract]
[WebInvoke(UriTemplate = "GetData/{ID}/{Name}", Method = "GET",
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest)]
string GetData(string ID, string Name);
}
My question is what are the possible implications of using both OperationalContract and WebInvoke, if any? Are there downsides?
Should I keep it as it is, in case later I might need to add a REST endpoint? Or should I remove WebInvoke?
My question is what are the possible implications of using both
OperationalContract and WebInvoke, if any? Are there downsides?
No, there are no downsides, other than you are adding code which may never be used.
Also, for your info, OperationContract is for all WCF operations, not just for SOAP operations. You need it for REST also.

How to call a dualHttpBinding(callback contract) from a webHttpBinding service in WPF

Hi all I am facing one issue with dualHttpBinding and webHttpBinding in my application. Here is the overall scenario
I have a dotNet and Android application which consumes a WCF Service (which has three different bindings).
1. basicHttpBinding - For dotNet app (Service1.svc)
2. webHttpBinding - For Android to access via Rest full service (Service2.svc)
3. dualHttpBinding - For push notification to dotNet app(PushServie.svc)
When ever android app consumes a method in Servie2(AddOrderItems) - it inserts into database and in inturn shows a message in dotNet application (a push notification). For this I have used CallBackContract in PushService and it is working fine when I try to access the AddOrderItems method (in Servie2) from dotNet app (for testing purpose I did) and notification message is coming.
But my problem is how can I come to know whether and and when my AddOrderItems is being called from android app, so that I have to show a message (via CallBackContract) in dotNet app.
I tried to call PushServie.svc method(CallBackMessagge) from Servie2.svc after calling AddOrderItems method but no luck at all.
Here is the code for Service2 and PushService.svc,
// AddOrderItems method in IService2 which is implemented in Servie2.svc
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "AddOrderItems", RequestFormat =
WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare)]
bool AddOrderItems(RequestOrderItemData orderItemData);
and call back method in IPushService which is implemented in PushService.svc
[OperationContract(IsOneWay = true)]
void DisplayMessage(int orderID, int tableID, string tableName);
Here is the code for DisplayMessage in PushService
IPushNotificationCallBack Callback
{
get
{
return
OperationContext.Current.GetCallbackChannel<IPushNotificationCallBack>();
}
}
and the method in PushService.svc
public void DisplayMessage(int orderID, int tableID, string tableName)
{
Callback.DisplayMessage(orderID, tableID, tableName);
}
I tried to search in googles and every one says that a webHttpBindin does not support a callback functionality.
My concern is I want to call my DisplayMessage method from AddOrderItems. If this can be possible with any modifications, I am really be in happy.
As far as I think I have posted all the necessary code, if some thing else requires, please let me know, I will post it.
Any help highly appreciated.
Warm Regards,
Ganesh

Enable both GET & POST call on an operation contract

Can I make an operation contract accessible on both GET & POST method?
Do we have any attribute or property for it?
I am able to call it on either POST with following attribute
[WebInvoke(ResponseFormat = WebMessageFormat.Json)]
or on GET with following attribute
[WebGet(ResponseFormat = WebMessageFormat.Json)]
or
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json)]
but I want to call the operation contract on both requests. Any suggestion on how to achieve this
Thanks in advance.

Customized message for endpoints not found in WCF Rest Service

I am using WCF to create a ReSTful service. Say my OperationContract is like this:
[OperationContract]
[WebGet(
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "GetItemList/{token}/{value}"
)]
Stream GetItemList(string token);
So when I call http://example.com/Service1.svc/GetItemList/myToken/myValue the service will be called.
Now I want to write a default method saying something link, 'No Method/End point exists', wen the user calls
http://example.com/Service1.svc/GetItemList/myToken/ or
http://example.com/Service1.svc/GetItemList/myValue/ or
http://example.com/Service1.svc/GetItemList/
How can I implement that in my code?
Right now what I'm doing is like:
[OperationContract]
[WebGet(
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "GetItemList/"
)]
string ValidateItemList();
[OperationContract]
[WebGet(
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "GetItemList/{Val1}"
)]
string ValidateItemList(string Val1);
And in the function, I just return a string saying "No method Exists".
Is there a better way? Can I customize error messages, for urls that are directed to my service? Say, a common message for all non existing url requests, that are directed to my service?
Basically, the architecture of WCF attempts to abstract the low level components of any protocol (in this case http) away so you don't have to worry about these types of details. Unfortunate;y, that engine does not expose a nice way to handle the request's that the engine cannot route correctly.
In this case, the URI cannot be "dispatched" to the correct contract implementing class. the engine has these wonderful components called, wait for it, Dispatchers, which can be customized within the wcf framework, either by configuration or programmatically. The problem is that they are a serious pain to implement. I have implemented the unexpected message dispatcher in my answer to another question, listed below:
Handling Invalid URI passed to a WCF service
Let me know if you need any further information!
I didn't find any feasible solution for my above problem. But I have found an alternate option. With VS 2012, Microsoft has released ASP.NET Web API. Which, they say, is the next version of WCF Rest. So in thet, you could handle these situations very easily. We can use the routing method in it.
Anyone intrested for that solution, can look into this post for a head start: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

wcf get method - how to bind to view model?

This is what I have in the service contract:
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[OperationContract]
string HelloWorld(HelloWorldViewModel vm);
where HelloWorldViewModel has properties X and Y.
If I do localhost/webservices/HelloWorld?X=1&Y=2, and set a breakpoint in the HelloWorld method, vm will be null. It does not automatically bind the passed-in query string params into a view model object.
Am I missing something? Thanks!
The behavior you described is implemented specifically in ASP.NET MVC model binding.
If you want to pass a complex object to a REST service operation using the WCF Web Programming Model, you'll have to include it in its serialized form in the body of an HTTP POST request.
In your case, based on the attributes placed on the HelloWorld service operation, the request's payload should look something like this (note that XML namespace declarations are omitted):
<HelloWorld>
<vm>
<X>1</X>
<Y>2</Y>
</vm>
</HelloWorld>
Related resources:
WebMessageBodyStyle Enumeration
vm == null is correct. It have to be sent as media parameter to your uri to be non null.
To get your parameters try to inspect:
WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters["X"]
or ...QueryParameters["Y"]
WCF [WebGet] operations only support primitive types by default. If you want to add support for other types, you can either create a type converter or a new QueryStringConverter that supports your type. You can find more information at http://blogs.msdn.com/b/carlosfigueira/archive/2011/08/09/wcf-extensibility-querystringconverter.aspx.
Another option would be to pass the parameter in the request body, but that would mean using a HTTP verb other than "GET", since GET requests cannot have body.

Categories

Resources