WCF Rest GET with multiple parameters - c#

I have a WCF Rest Service and an OperationContract defined in the following way:
[ServiceContract]
public interface IMyService {
[OperationContract]
[WebInvoke( Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "get/{filename}" )]
MyFileStructure GetFile( string filename );
}
The Server stores some files and the GetFile() retrieves some information from the specified file in the GET request and put them in a MyFileStructure instance which is then JSON parsed and returned back to the client.
E.g. the user can get data from the file named myfile.xml, just typing the following on the browser: http://localhost:[port]/MyService.svc/get/myfile
(the file extension is always ".xml").
This works fine.
The question:
I now need to customize this request a bit more, passing some parameters to my file request. Basically, each stored XML file contains a set of attributes, which can be different (in attribute names and size) from file to file. Please notice that a domain of these attributes does not exist. Each parameter in the request should refer to a specific attribute of the specified file, but since the attributes defined in the file are not known, I cannot use the following:
[OperationContract]
[WebInvoke( Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "get/{filename}?param1={param1}" )]
MyFileStructure GetFile( string filename );
I would like to be able to pass my parameter list in a standard GET request, e.g.:
http://localhost:[port]/MyService.svc/get/myfile?myparam1=value1&myparam2_value2&...
but, at the same time being able to receive that as a single string/whatever object on the server side, in order to process the parameters based on the selected file. Is that possible? How?

You can receive a json object with any parameters you want or a key value pair object, like a dictionary, as it follows:
MyFileStructure GetFile( string filename, [FromBody]IDictionary<string, string> params);
And in javascript:
var parms = {};
parms['param1'] = "one";
parms['param2'] = "two";
$.ajax({
url: '/api/GetFile?filename=' + filename,
data: JSON.stringify(parms),
contentType: 'application/json'
type: 'POST',
dataType: 'json'
});
Hope it helps.

From the question I didn't understand if it is critical to use only GET requests or not.
But if it is, one more options could be usage of http headers. You can pass any header you want from the client, do then a GET request and then access these header in your service using weboperationcontext.current.incomingrequest.headers.
You can check here if some header specified and run some specific code for it, otherwise check another header and so on.
And yes WebAPI, is a kind of symbiosis of WCF and ASP.NET which is preferably now for RESTful API development. But you can use headers there as well.

I think it is not a good idea to use GET Http verb for method which takes a multiple parameters as input data. In this case I would recommend to use POST Http Verb. Something like that:
[OperationContract]
[WebInvoke( Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = **WebMessageBodyStyle.WrappedRequest**,
UriTemplate = "/getFiles" )]
MyFileStructure GetFile( List<string> filenames );
It will be a little bit comfortable to use and it also has a serious advantages over sending data via Get request such as safety. If you will have a lot of parameters you may lost some of them because of max length of url (which equal to 2000 characters). Using post request you can avoid this problem

My best bet is use a post request to do it. You can use Stream as parameter in method and which will gain you to read and save file stream and other data also.

Related

WCF “At most one body parameter can be serialized without wrapper elements”

I'm trying to consume my WCF webservice via an MVC Web Application. I add a service reference via the Add service reference dialogue in VS. Now when I try to call my proxy.LoginUser I get the error message:
Operation 'GetAlertNotification' of contract 'IService1' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements. Either remove the extra body parameters or set the BodyStyle property on the WebGetAttribute/WebInvokeAttribute to Wrapped.
The only problem is there is no body parameters in GetAlertNotification?? If I understand correctly if I pass all parameters via the query string this should not be an issue? Here is the signature of GetAlertNotification in IService:
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/GetAlertNotification?project={project}&currentversion={currentversion}&EncryptData={EncryptData}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
AlertNotification GetAlertNotification(string project, string currentversion, bool EncryptData = false);
Edit:
I replaced WebInvoke by WebGet and still get the error message above. How can it say it has multiple request body parameters with everything specified in the UriTemplate? I'm I not understanding what the error is saying? Anynone?

Is it possible to use both GET and POST in a same method?

I would like to know, in a wcf rest service is it possible to use both HTTP POST and HTTP Get in same method? I mean to say that a client page can either use post or get to invoke my method.
My client wants me to implement a method in this way.
As our API is a "RESTful" service we should be able to use both GET
and POST with this method. The parameter can be placed in the URL
of a GET request and also in the Header section of the GET request. When
using a HTTP POST with this method the parameter can be
stored in the header section or the body.
Is it possible?
Lets do it by writing code! Suppose you have a method!
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "Leads",
ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare)]
[WebGet(UriTemplate="/Leads")]
Result AddLeads(ReqLead[] rl); // This is our method.
When you will run your service, it will compiled and run successfully and browser will display you a page.
Now green arrow pointing is my Service name. By cliking on it will redirect you an error page and it will make an idea clear to you! See the image below.
I hope it will give you an idea. Moreover! In you [OperationContract] you will define only one method type, whether GET or POST. You can't have both.
Thanks

Some characters in WCF REST parameter from UriTemplate are HTML encoded

I have the following Web Service interface (a WCF service) method defined:
[WebInvoke(Method = "POST", UriTemplate = "sites/{siteId}/storage/{*filePath}", BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
FileUploadResultDto UploadMultipart(Stream fileData, string siteId, string filePath);
If I do a HTTP POST request to: "(host)/sites/1234/storage/%D0%BC%D0%B0%D0%BC%D0%B0.html" (this is the URL-encoded version of "мама.html")
Parameter filePath is read as "мама.html", which is wrong.
I'd like it to be directly read as "мама.html".
However, "м" is the html-encoded version of the "м" character.
Why is WCF/UriTemplate behaving this way? How can I directly obtain a direct representation of the string, and not have some of the character html-encoded? Is there a setting in web.config for this? Is it a bug?

WCF Rest Change name of root return element

I have
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "projects/{projectname}")]
[return: MessageParameter(Name = "ProjectId")]
Guid CreateProject(String projectName);
But this still returns
<guid
xmlns="http://schemas.microsoft.com/2003/10/Serialization/">00000000-0000-0000-0000-00000000</guid>
How do I replace "guid" with ProjectId?
public Guid CreateProject(String projectName)
{
return Guid.Empty;
}
If I change the OperationContract BodyStyle to WrappedResponse I get:
<CreateProjectResponse
xmlns="http://tempuri.org/">
<ProjectId>00000000-0000-0000-0000-000000000</ProjectId>
</CreateProjectResponse>
Which is almost what I want, but I don't want unnecessarily wrapped.
You become what you have defined. You have defined to receive empty GUID in XML form and it returns to you empty GUID in XML. All is right.
Maybe you need convert GUID to some kind of string id, then Guid.NewGuid().ToString("N")
When you aren't expecting xml then you need to fit attributes and use HTTP Accept Header from client, for example for Json Accept: application/json, or string - plain/text
UPD:
Now a little bit clear. Your actually ask how to change XML structure. I recommend you for standard types use standard XML structure because you already have implemented from the box XML formatters. Anyway when you need to change formatters, you can do it by extending the WebHttpBehavior and overriding the WebHttpBehavior.GetReplyDispatchFormatter method to return our own custom implementation of System.ServiceModel.Dispatcher.IDispatchFormatter (as example read here)
I want also just mention, that you are using WCF 4 REST, and this technology is legacy. When you are dealing not with legacy project or maintenance, then I recommend you to use ASP.NET Web API, because this and many other things could be done there much more easier.
Easiest solution is to
return new XElement("ProjectId", Guid.Empty);
Not really what I wanted, but it works.

Multiple parameters passed in WCF client don't work (even when WebMessageBodyStyle is Wrapped)

Hi fellow StackOverflowers,
I've got a WCF service wrtten C# that i can succesfully consume from things like jquery.
I want to be able to consume it by adding a web service reference in C# and making calls in the code. Everything was rosy, until I added multiple parameters. When I try to call any Service method, I get this error:
Operation 'GetStopNames' of contract 'IPublic' specifies multiple
request body parameters to be serialized without any wrapper elements.
At most one body parameter can be serialized without wrapper elements.
Either remove the extra body parameters or set the BodyStyle property
on the WebGetAttribute/WebInvokeAttribute to Wrapped.
I googled and searched StackOverflow for ages, but everybody seemed to have their problem fixed by setting
BodyStyle=WebMessageBodyStyle.Wrapped
in the WebGet / WebInvoke attributes.
An example of one of my service methods in the interface:
[OperationContract]
[WebGet( BodyStyle=WebMessageBodyStyle.WrappedRequest
, UriTemplate = "GetOperators?appKey={apk}"
, RequestFormat = WebMessageFormat.Json
, ResponseFormat = WebMessageFormat.Json)]
ResultList GetOperators(string apk);
Is there something wrong with this?
I'm simply calling
ServiceReference1.PublicClient c = new ServiceReference1.PublicClient();
c.GetOperators("XXX");
inside the client, and it's breaking on the second line.
Any ideas? If there is any more data you need to help answer me, just add a comment :)
EDIT:
here are the excerpts of relevant bits from my Web.config files
http://pastebin.com/CyQNG6wk
EDIT:
shortcut to serviceContract that I linked in comments
http://pastebin.com/bvGmGtfd
I ended up switching to using WebApi but I'm keeping this question open since I'm still not sure why it was failing.
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "GetOperators?appKey={apk}",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,RequestFormat=WebMessageFormat.Json)]
ResultList GetOperators(string apk);
In the .svc file make sure Service="Developer_Portal.Public"
Its the problem in GetStopNames. I assume it is Http Get (WebGet). Make sure all the parameters it accepts are defined in uri template
GetStopNames(string p1, string p2, string p3)
uri = "GetStopNames/{p1}/{p2}?param1={p3}" or GetStopNames?param1={p1}&param2={p2}&param1={p3} or whatever combination
You cannot generate proxy for rest by adding service reference. Do you have soap based service with same interface also?

Categories