WCF custom datatype as OperationContract parameter - c#

I'm very new to WCF and have a question that I hope you can help me with.
Project: I've been asked to create a WCF service that allows a client to be able to upload a word file along with some metadata.
The client doesn't have a sample of the POST call they'll be making so I can't create a class off of that WSDL, but the post would contain data like this:
{
author: 'John Doe',
pages: '32',
size: '14432',
authToken: '322222222233',
encoding: 'binary'
name: 'Document1.doc'
}
I'm thinking of creating an [OperationContract] such as bool UploadFile(CustomDocument inputDocument) instead of bool UploadFile (string author, string encoding ....).
My question: If I use a custom object as an input parameter (CustomDocument) for an [OperationContract] would the client be able to pass all the information as string, int etc in its service call, or would they have to first create an instance of CustomDocument on their end, and then include that object in the post?
Sorry, I'm very new to WCF, my apologies in advance if this question doesn't make any sense; I'll update it based on your feedback.

You have to make sure that CustomDocument is a Serializable object and have a public parameterless constructor.
The easiest way is share the dll that contains the class CustomDocument between the WebService and the Application that will use it.
But personally when I try to send a complex object to a WebServce I prefer to serialize as a byte array and then Deserialize inside the WebService.
Good luck!

You don't need the custom object CustomDocument. Suppose you have this service
[ServiceContract]
public interface IMyTestServce
{
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "/Upload?author={author}&pages={pages}&size={size}&name={name}&authToken={authToken}")]
void Upload(string author, int pages, long size, string name,
string authToken,
Stream file);
}
public class MyTestService : IMyTestServce
{
public void Upload(string author, int pages, long size, string name,
string authToken,
Stream file)
{
Console.WriteLine(String.Format("author={0}&pages={1}&size={2}&name={3}&authToken={4}", author, pages, size, name, authToken));
Console.WriteLine(new StreamReader(file).ReadToEnd());
}
}
You can easily call it like
HttpClient client = new HttpClient();
var content = new StreamContent(File.OpenRead(filename);
await client.PostAsync("http://localhost:8088/Upload?author=aa&pages=3&name=bb&authToken=112233", content);
PS: You need to use webHttpBinding (or WebServiceHost if it is not hosted in IIS).

Related

Self Hosted REST Web Service not accepting POST with parameters

Hopefully a simple question, but I have a simple app that is self-hosted (which works fine), and I can hit the requested method using a POST without parameters from the body (which hits the method but defaults the parameter to null), but when I try to pass the named parameter in the BODY of the POST request in raw JSON format, it receives a 400 response, and never hits the method for some reason...
Any advice is appreciated.
[Environment: Visual Studio 2015, C#, self hosted REST application]
[Code Details]
(Web service hosting code for Self Hosted app)
WebServiceHost host = new WebServiceHost(typeof(CalculatorServiceREST), new Uri("http://localhost:8000"));
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(ICalculator), new WebHttpBinding(), "");
ServiceDebugBehavior stp = host.Description.Behaviors.Find<ServiceDebugBehavior>();
stp.HttpHelpPageEnabled = false;
host.Open();
Console.WriteLine("Service is up and running");
Console.WriteLine("Press enter to quit ");
Console.ReadLine();
host.Close();
(The contracts implementation class: CalculatorServiceRest.cs)
public class CalculatorServiceREST : ICalculator
{
[WebInvoke(Method = "POST")] // POST to: /RoundUp (with BODY item of 'number' in the request)
public int RoundUp(double number)
{
return Convert.ToInt32(Math.Round(number));
}
[HttpPost] // POST to: /GetName (with BODY item of 'number' in the request)
public string GetName(string name)
{
return name;
}
}
It appears that I have to add the following attribute values to the POST method so that I can pass JSON data in the BODY for it to pick it up (which is different from how I am use to being able to just put [HttpPost] attribute for MVC and it just knows how to pick it up. Can anyone provide some insight on why it is different?
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]

Web API and C# out Values

I have a service that contains a lot of functions with out parameters to return a few extra parameters.
I was wondering if it's possible to call a regular asp.NET web api service with out parameters and receive a value(in the form of out parameters, separate from the return value) from the service.
If it is possible, could you elaborate on what I need to do to achieve this?
Any help will be well appreciated.
No, this is not possible. The response from WebAPI will be a normal HTTP response with a body where the serialized returned data will be.
Of course, as usual, your response can be a complex object to serialize and you can include those out returns as members of it. For example:
public IHttpActionResult GetResponse(int id)
{
int outputInt;
string outputString;
YourMethodWithOutParameters(id, out outputInt, out outputString);
return Ok(new
{
Id = id,
OutputInt = outputInt,
OutputString = outputString,
});
}

How to use UriTemplate?

I have below OperationContract in my WCF web service.
[OperationContract]
[WebGet(UriTemplate = "/publisheddata/{number}/{*publication}")]
Message GetPublished(String number, String publication);
[OperationContract]
[WebGet(UriTemplate = "/unpublisheddata/{number}/{*publication}")]
Message GetUnPublished(String number, String publication);
I want to call one common method for above both OperationContract, means in the Service implementation code I will call the Stored Procedure on the basis UriTemplate called, I know i can easily do by adding extra attribute in above url, I don't want to ask user to put it from the url.
Here I want to write condition on the basis of UriTemplate called, so my above code become as below:
[OperationContract]
[WebGet(UriTemplate = "/publisheddata/{number}/{*publication}")]
Message GetData(String number, String publication);
[OperationContract]
[WebGet(UriTemplate = "/unpublisheddata/{number}/{*publication}")]
Message GetData(String number, String publication);
In my Service implementation, I want to check if unpublisheddata then GetUnPublished else if publisheddata then GetPublisheddata
Is it possible or suggest better ways to implement it?
firstly, -probably- you'll get exception because of your method names. you can't use same method names like yours, but you can use OperationContract property "Name"
[OperationContract(Name="GetPublished")]
Message GetData(String number, String publication);
[OperationContract(Name="GetUnPublished")]
Message GetData(String number, String publication);
if you prefer single method, you can modify your method like this
[OperationContract]
[WebGet(UriTemplate = "/{publicationType}/{number}/{*publication}")]
Message GetData(string publicationType, string number, string publication);
and in your method you check "publicationType" parameter and do your logic
if I understand truly, you want provide access only single method. I'm using a structure like this in my project
[WebInvoke(Method="POST", UriTemplate ="/customers", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json), Description("Save a customer information")]
OperationResult CustomerSave(Request<Customer> customerRequest);
and also I have 2 different methods -not show in WCF interface / contract- that names "Create" and "Update"
in my wcf method (CustomerSave), I'm doing process like this
if(customerRequest.Id != Guid.Empty)
{
Update(customerRequest);
}
else
{
Create(customerRequest);
}
and my users can not see Create / Update methods

How to make REST based WCF service Service file be index?

I have a service file, Service.svc that provides a Web Service. I would like the help page to be the main url (e.g. / instead of /Service.svc/help). Is this possible and can someone tell me how do do it?
Just redirect to help page. For example:
[WebInvoke(UriTemplate = "", Method = "GET")]
public void RedirectToHelp()
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Redirect;
WebOperationContext.Current.OutgoingResponse.Location = "help";
}

WCF UriTemplate with large query strings

I'm working with a rather large query string(~30+ parameters) and am trying to pass them to a WCF service I've setup.
I've run into a few issues specifically with the UriTemplate field. This service is setup to access a third party Api, so the query string may or may not contain all parameters. I'm curious if the best approach is to build a query string and pass that to the WCF service or to pass each parameter(and in some cases String.Empty) individually.
I've currently tried to dynamically build up a query string, however have hit a wall with either a 403 error when I try to pass the entire string( "?prm1=val&prm2=val" ) into the uritemplate of "ApiTool.jsp{query}", or I hit an invalid uritemplate response due to the fact I don't have name/value pairs listed.
I am pretty sure you'll need to list the parameters individually. Otherwise, UriTemplate will end up escaping things for you:
var ut = new UriTemplate("Api.jsp{query}");
var u = ut.BindByName(new Uri("http://localhost"), new Dictionary<string, string>() { { "query", "?param1=a&param2=b" } });
Console.WriteLine(u); // http://localhost/Api.jsp%3Fparam1=a&param2=b
You can 'unescape' querystring with IClientMessageInspector.
public class UriInspector: IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
// change/replace request.Headers.To Uri object;
return null;
}
}
See MSDN how to add this to your Endpoint object.

Categories

Resources