Relationship between WCF Operation Name and Action - wcf

I have a WCF service defined like this:
[ServiceContract(Namespace = "http://AttributeServiceNameSpace", Name = "AttributeServiceName1")]
public interface IHelloIndigoService1
{
[OperationContract(Name="AttributeOperationName11", Action = "aaa2")]
String HelloIndigo11();
[OperationContract(Name = "AttributeOperationName12", Action = "aaa1")]
String HelloIndigo12();
}
And I captured the HTTP message during the service invocation, as below.
POST http://xxx/Service.svc/IHelloIndigoServiceAddress1 HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "aaa2"
Host: shao-02.fareast.corp.microsoft.com
Content-Length: 162
Expect: 100-continue
Connection: Keep-Alive
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<AttributeOperationName11 xmlns="http://AttributeServiceNameSpace"/>
</s:Body>
</s:Envelope>
So we can see the Action and Operation Name both exist in the SOAP message to invoke the service.
But I just wonder:
Why do we need the Action and the Operation Name to identify a single service method? Only one should be enough.

You don't need Action and OperationName to identify service operation. Operation name defines structure (wrapper element name) of the SOAP message but it is not used for operation identification. The action is used for operation identification.
There are some non standard SOAP parsers using operation name (root body element) for operation identification but those parsers don't use SOAP action.
Edit: I had a discussion with my colleague today and it looks like my previous answer isn't correct. The real unique identification of the message in SOAP protocol is SOAP Action + Root element. So in this case the Action defines SOAP Action and OperationName defines wrapper element's name (used as root message element).

Related

RAML, specify API request Content-Length value

I'm trying to set the value of the Content-Length property to 0 in my RAML file.
I first stumbled upon this thread : How to specify API request header value in RAML
When I tried implementing it with this code :
/update:
post:
description: Store updated data in database
headers:
Content-Length:
enum: [0]
body:
...
I got the response 400 Bad Request :
{
"code": "REQUEST_VALIDATION_ERROR",
"message": "Required header Content-Length is missing."
}
My IDE told me a string was expected but feeding with ["0"] didn't solve the problem.
(I'm testing my API specification in Mulesoft Design Center.)
So is there something I did wrong or is there another way to set the Content-Length to 0 in the request's header ?
You should only try to define custom headers in RAML. A required header of the HTTP protocol like Content-Length must not be defined. It should be automatically generated to prevent errors.

WebAPI HttpResponse Message

For WebAPI2 Action results, HTTPResponseMessage is used as one of the return type and Request.CreateResponse is used to return the message.
Request.CreateResponse is handy when we want to return single instance of the model but if we want to return multiple rows from the “model”, there is no overload method for Request.CreateResponse or Request.CreateResponse which supports it(as far as I read). If someone could post the sample, it would be great
Also, I have few other queries.
• Why we have to go for HttpResponseMessage rather than IQueryable or Model return type?
• What is the difference between Request.CreateResponse and Request.CreateResponse , as we are able to return a single instance of the model using both methods. How we can choose one among the two?
You can make the return type of your action method be any serializable data. Content negotiation and formatters will turn the returned value into an HTTP response for you.
From Action Results in Web API 2:
Other Return Types
For all other return types, Web API uses a media formatter to serialize the return value. Web API writes the serialized value into the response body. The response status code is 200 (OK).
public class ProductsController : ApiController
{
public IEnumerable<Product> Get()
{
return GetAllProductsFromDB();
}
}
A disadvantage of this approach is that you cannot directly return an error code, such as 404. However, you can throw an HttpResponseException for error codes. For more information, see Exception Handling in ASP.NET Web API.
Web API uses the Accept header in the request to choose the formatter. For more information, see Content Negotiation.
Example request:
GET http://localhost/api/products HTTP/1.1
User-Agent: Fiddler
Host: localhost:24127
Accept: application/json
Example response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
Date: Mon, 27 Jan 2014 08:53:35 GMT
Content-Length: 56
[{"Id":1,"Name":"Yo-yo","Category":"Toys","Price":6.95}]

Fiddler POST Invalid Header Name

I am sending a POST request to a WCF Web service using fiddler, and the service responds with HTTP 400: The request has an invalid header name.
The post request looks like this:
User-Agent: Fiddler
Host: localhost:49392
Content-Type: application/json
Content-Length: 0
{ "clientFirstName" : "John"}
My endpoint is defined as follows:
[OperationContract]
[System.ServiceModel.Web.WebInvoke
(Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Json,
BodyStyle = System.ServiceModel.Web.WebMessageBodyStyle.Wrapped,
UriTemplate = "MakeReservation")]
String MakeReservation(Stream reservationStream);
MORE
First of all, the JSON was in the wrong pane. I moved it to the Request Body pane.
I changed the prototype of the function to take a String instead of Stream as the input parameter. The service now accepts my call and returns 200, but in the debugger I see that the input parameter String is null. When I change it back to Stream, I get 400 again.
YET MORE
Enable tracing gives me at trace file with the following message:
Incoming message for operation 'MakeReservation' (contract 'ITalLimoService' with namespace
'http://tempuri.org/') contains an unrecognized http body format value 'Json'. The expected body
format value is 'Raw'. This can be because a WebContentTypeMapper has not been configured on the
binding. See the documentation of WebContentTypeMapper for more details.
As noted int the WebInvoke definitiuon, both the RequestFormat and ResponseFormat are set to WebMessageFormate.Json. Why is IIS complaining about this?
I don't know why this works, but for some reason removing the following line from the fiddler Composer did the trick:
Content-Type: application/json
And that is that. I would give points for an explanation.
I know this post is old. But very strange, when I removed the header "application/json" it worked.
Has it got to do with server setup?
The request could not be understood by the server due to deformed syntax. The client SHOULD NOT repeat the request without modifications.If request to your server with data that is in the correct format, but its bad data. eg: a Posted String value to an API endpoint that expected a String value; but, the value of the string contained data that was something else.
The syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains syntactically correct but semantically wrong XML instructions.

WCF OData patching an entity set

Is it possible in update multiple entites based on a filter query in a batch request?
As an example of what I'm trying to achieve, say I want to update all product categories from foo to bar in one request to an OData endpoint, is there something like this that would work:
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: multipart/mixed; boundary=changeset_fa7b-4aa9-a01f
GET /api/products?$filter=category eq 'foo' HTTP/1.1
Accept:application/json
Content-ID: 1
--changeset_fa7b-4aa9-a01f
Content-Type: application/http
Content-Transfer-Encoding: binary
PATCH $1 HTTP/1.1
Accept: application/json
Content-Type: application/json;odata=verbose
{"category":"bar"}
--changeset_fa7b-4aa9-a01f--
--batch_36522ad7-fc75-4b56-8c71-56071383e77b--
I'm afraid the answer is no. There's no support for that in the protocol. And even if you remove the filtering from the question, trying to update all entities in the entity set so that they will have a same new value, the answer is still no.
You could probably do this yourself. Like,
Get /service.svc/MyEntitySet
and for every entity you get back, send a PATCH to update it individually.
In addition, if this kind of operation is going to be done frequently, the service author could write a specific service operation or action to do this on the server side. For example, write something called "ClearAllNames", and a user could invoke that, and the server would go through every entity and clear its name field.

Accessing the HTTP headers from a WCF Service

I need to access the HTTP response headers that are to be returned to the client from a WCF Service. Accessing the HTTPContext is easy(through HttpContext.Current.Response), but what is the event/extension/behavior that is executed lastly, when the StatusCode is already set (for ex. if the status is 500)?
EDIT: Message Inspectors don't seem to be a good solution here, because at the time they run, the status code isn't set yet. (At least in my trial that was the case)
You can access all headers on WebOperationContext.Current.IncomingRequest, like this:
IncomingWebRequestContext request = WebOperationContext.Current.IncomingRequest;
WebHeaderCollection headers = request.Headers;
Console.WriteLine("-------------------------------------------------------");
foreach (string headerName in headers.AllKeys)
{
Console.WriteLine(headerName + ": " + headers[headerName]);
}
Console.WriteLine("-------------------------------------------------------");
See here
Simplest way for having control on the Headers is to use Message contracts.
Use Message Inspectors to monitor the message right after receiving it at the Service end.
In an extreme case, where you are not satisfied with any other standard routes, you can go for POX (Plain Old XML) type operations where you would be dealing with raw XML message.