Upload file together with multiple parameters using restful wcf - wcf

I am trying to create a wcf rest service using visual studio 2012 and .net framework 4.5.
The service will try to upload a file together with 4 or more parameters. I want to do this in only one call. I want to use the http "put" method. But I keep having these 2 errors.
Operation 'AddFile' in contract 'IRestBasketService' has multiple request body parameters, one of which is a Stream. When the Stream is a parameter, there can be no other parameters in the body.
(When I am using BodyStyle wrapped)
and
Operation 'AddFile' of contract 'IRestBasketService' 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.
(When I am using BodyStyle bare)
What should I do ?
Bellow are the 2 signatures giving me the errors
[WebInvoke(Method = "PUT",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "AddFile?key={key}&email={email}&fileName={fileName}&groupID={groupID}&ID={objectID}")]
Response AddFile(string key, string email, string fileName, string type, string objectID, string groupID, Stream fileStream );
[WebInvoke(Method = "PUT",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json,
UriTemplate = "/AddFile")]
Response AddFile(AddFileRequest request, Stream FileStream);
I'm using the webHttpBinding and the webHttp behaviour in the web.config.

Since you're using Stream as one of the input parameter, there can be no other parameters in the body. You would need to add all the extra data as part of the stream in the client and then parse it in the service.
1. Similar problem
2. Similar problem

Related

Passing complex type to WCF Rest service with stream as another parameter

I am trying to create a wcf rest service using visual studio 2012 and .net framework 4.5. The service will try to upload a file together with 4 or more parameters. I want to do this in only one call. I want to use the http "put" method. But I keep having these 2 errors.
Operation 'AddFile' in contract 'IRestBasketService' has multiple request body parameters, one of which is a Stream. When the Stream is a parameter, there can be no other parameters in the body.
(When I am using BodyStyle wrapped)
and
Operation 'AddFile' of contract 'IRestBasketService' 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.
(When I am using BodyStyle bare)
What should I do?
Below are the 2 signatures giving me the errors
[WebInvoke(Method = "PUT",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "AddFile?key={key}&email={email}&fileName={fileName}&groupID={groupID}&ID= {objectID}")]
Response AddFile(string key, string email, string fileName, string type, string objectID, string groupID, Stream fileStream );
[WebInvoke(Method = "PUT",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json,
UriTemplate = "/AddFile")]
Response AddFile(AddFileRequest request, Stream FileStream);
I'm using the webHttpBinding and the webHttp behaviour in the web.config.

WCF Return different fault depending on RequestFormat

I have a WCF method:
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "exception")]
public void GenerateException()
I want to return a different fault based on the client (SOAP vs JSON) because they don't seem to have visibility to the message if I don't.
So I check the content type and choose my type accordingly
String ct = WebOperationContext.Current.IncomingRequest.ContentType;
FaultException fe = new FaultException(errorMessage, new FaultCode(errorCode));
WebFaultException<ErrorData> errorDataWebFault = new WebFaultException<ErrorData> (errorData, System.Net.HttpStatusCode.InternalServerError);
if (ct.Contains("text/xml"))
throw fe;
else//Can throw any of the WebFaultExceptions here
throw errorDataWebFault;
If I don't check, SOAP consumers can't see the message of WebFaultExceptions, and JSON consumers cant see the message of the FaultException.
Is there a better way to do this? Feels like there should be something "built in".

WCF RESTful service which accepts a file as input

Being completely new to WCF, I'm trying to make a RESTful service which will accept a file (the file is usually text with comma/tab-separated values) and a delimiter as parameters, parse the file and do some calculations. Based on what I read in others posts, I assume that the WCF service needs to save the file on the server first.
EDIT: I presume the answer is something similar to the one answered here, but I'm also interested in the code not mentioned in the answer.
Here is the interface method:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "dataSets/{dataSet}/metadata?delimiter={delimiter}&format=json",
BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
void PostMetadataJSON(Stream dataSet, char delimiter)
{
}
And here is the method in the class implementing the interface:
void IMyService.PostMetadataJSON(Stream data, char delimiter)
{
//the delimiter is needed for splitting each line of the file
}
Can someone explain the approach to follow? I've found some examples on SO but they only got me more confused as I am completely new to this.
Just use WCF's streaming support
http://msdn.microsoft.com/en-us/library/ms733742.aspx

How to define attributes to upload data to a REST web service implemented through a WCF service?

I created a WCF service, that returns some data and also allow to post some data to.
The methods of the service are as below:
[OperationContract]
bool UploadStream(Guid key, List<StreamRecord> values);
[OperationContract]
bool RegisterStream(Guid key);
[OperationContract]
StreamCollection GetStreams(Guid key);
I need to implement this with a REST interface.
I created a new interface, IRestService as below
[WebInvoke(
Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
UriTemplate = "/bitpool/{poolKey}/streams")]
BitStreamCollection GetBitStreams(string poolKey);
and it works ok (I can test it from the browser address bar and all is fine)
Now I want to implement also the Upload method, but I'm not sure how to do it
I tried with
[WebInvoke(
Method = "POST",
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
UriTemplate = "/stream/{streamKey}/records/{values}")]
bool UploadStream(string streamKey, List<StreamRecordEntity> values);
But when I try to access the service in browser it gives error
http://localhost:6767/RestServer.svc/
it gives an error:
Operation 'UploadBitStream' in contract 'IRestServerJson' has a path variable named 'values' which does not have type 'string'. Variables for UriTemplate path segments must have type 'string'.
I think for POST I cannot define such URL, but how should I do it?
Also, method RegisterStream should check if stream with key exists and if not, create it and return true, otherwise return false.
Should I define it as GET (since it must return result) or as PUT or POST?
Thanks
Pass the values in the body of the POST request, formatted in xml, not on the url. An easy way to test this is to use Fiddler.
Regarding RegisterStream, both POST and PUT can return information in the response body. You could use POST and return an appropriate HTTP status code depending on the action taken by the server: 201 Created if the resource is created, a different status code that makes sense in your application if the resource already exists.
The caller can determine whether the resource was created or already existed based on the HTTP status code returned, so the bool return value wouldn't be needed.
Side note: you can use the [WebGet(...)] instead of [WebInvoke(Method = "GET"...)].

WebInvoke Method=“POST” or "GET" for a REST Service on WCF

When should use post vs get? in a REST service on WCF?, below is my interface
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
string DoLodge(string Id, Lodge value);
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
LodgeLevel[] GetLodgeLevels(string Id);
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
long GetLodgeCount(string Id);
POST should be used when sending an update back to the server.
GET should be used when retrieving an object from the server.
You might want to read up on what the HTTP Verbs mean in the context of RESTful services:
http://swdeveloper.wordpress.com/2012/03/04/rest-for-the-rest-of-us/
http://homepages.tig.com.au/~ijoyner/Ian_Joyner/REST.html
POST everytime you are modifying some state on the server like database update, delete. GET for readonly fetching like database select.
GET: Get a collection of entries (as a feed document) or a single entry (as an entry document).
POST: Create a new entry from an entry document.
PUT: Update an existing entry with an entry document.
DELETE: Remove an entry.
But in C#, you receive a response in GET.
so the complete answer will be,
GET should be used when retrieving an object from the server and used when sending an update back from the server.