I am trying to port some existing WCF code to Web API. The code acts as an interface for ADO.NET Sync Services and consists of the following method signatures...
[OperationContract]
SyncContext ApplyChanges(SyncGroupMetadata groupMetadata, DataSet dataSet, SyncSession syncSession);
[OperationContract]
SyncContext GetChanges(SyncGroupMetadata groupMetadata, SyncSession syncSession);
[OperationContract]
SyncSchema GetSchema(string[] tableNames, SyncSession syncSession);
[OperationContract]
SyncServerInfo GetServerInfo(SyncSession syncSession);
I then want to be able to call these methods from other .NET client applications, some of which will be on Compact Framework!
I have seen lots of suggestions and examples around the web as to the use of JObject, custom model bindings (with an encapsulating object) and even FormDataCollection - but all of these examples have JavaScript clients and I cannot then see how I might code a .NET client in such a way as to be able to pass all of the parameters correctly and also get back the results I am looking for (for example, are these PUT/POST as I am passing parameters as input, or GET as I am expecting content in the result)?
Can anybody offer any assistance here?
I have yet to determine how I name the methods in such a way as they can be called (I have found the ActionName attribute and the Http* attributes along with a custom routing example that allows the action name to be passed as a part of the URL but again I cannot really see how these map correctly to the HttpClient Get/Put/Post/Delete methods and of course the HttpClient is not - as far as I know - available on Compact Framework).
Related
For particular endpoints on my rest service I need to check a token, rather than doing this in each of those endpoints:
IncomingWebRequestContext woc = WebOperationContext.Current.IncomingRequest;
string tok = woc.Headers["tok"];
// validate etc
I'd like to put an attribute on the endpoint's method and do something like this:
[Restricted]
public Blog Get(string id)
And make the endpoint return custom responses, can I get headers and control method return values like this?
There is two ways to do this:
You can use an external tool like postsharp to implement aspect oriented programming. That means your attribute (plain metadata right now with standard .NET) becomes an Aspect and executes code. This is achieved through a post-compiler that weaves IL code. Cool stuff, but it costs money.
You write your own IEndpointBehavior to apply a dispatch behavior to your service endpoint, that in turn will add an IDispatchMessageInspector that can examine the message (for example for headers) and act accordingly for all messages to your endpoint. It could also check your endpoint actions, whether they have such an attribute set and act only on those that have it.
I have been provided with a WSDL and have generated the proxy class based on this WSDL. Sorry cannot provide the WSDL due to security concerns. The method in the proxy class that I'd like to call is:
public HeaderValueType GetStatus(System.DateTime RequestorTrxTime, string RequestorContext, string MessageIdentifier, string ProfileNumber, string ProfileType, int RequestIndicator, out ResponseBodyType Response) {//Some code}
I am just wondering what the fields
string RequestorContext, string MessageIdentifier
Are meant to be because I have seen requestorContext being passed as an object like this:
OperationContext.Current.InstanceContext
But not as a string the same goes for MessageIdentifier.
I have not got access to the creators of this WSDL for a while and cant get access, so I thought if any one would have a clue.
Did you try calling the service just be passing some values into these fields? It looks more like naming coincidence. Check that linked XSDs from WSDL specify this as message content. Also check that WSDL contains policy assertion called CompositeDuplex and assertions for reliable messaging (it should be called RMAssertion). It it doesn't it is not WsDualHttpBinding where InstanceContext is used to expose callback contract and those parameters are only data related - meaning of those parameters must be described by service provider.
I'm trying to understand WCF, so my questions may be dumb. I believe I have a firm understanding of "GET" operations. I'm now working on some "POST" operations. My question is, can I write a WCF Service operation, with WebInvoke, that accepts multiple parameters? Or, when I POST data, will it only accept a single serialized parameter?
Thank you!
Yes, but your POST will have to be passed in using a common understanding of the data, aka a "data contract".
In WCF, the typical approach here is that you'd create a contract class (just an off-my-head example, not 100% working))
[DataContract(Namespace="http://yournamespace.com")]
public class MyContract
{
[DataMember(Order=1)]
public string MyData1 { get(); set{};}
[DataMember(order=2)]
public string MyData2 { get(); set{};}
}
Then you'd specify your WCF operation to accept that contract type as its parameter
[WebInvoke(method="POST")]
public string DoSomethingFromPost(MyContract postedData)
{
}
On your client, you'd serialize the data to an xml/json that matches your contract. Again, loose example:
<MyContract xmlns="http://yournamespace.com">
<MyData1>value</MyData1>
<MyData2>value</MyData2>
</MyContract>
When the contract matches, WCF will deserialze your POST into your contract object, at which point you can use it like any other class.
It seems like there is a bit of confusion between wcf (which is the name given to microsofts overall abstraction for network programming) and a specific protocol HTTP, that defines verbs like "POST" and "GET", that wcf will be using to communicate.
When you define a wcf service operation and attribute it with [WebInvoke] you are going to access to the service using REST over HTTP. See webinvoke for more detail, however the remarks sum it up well
The WebInvokeAttribute attribute is
applied to a service operation in
addition to the
OperationContractAttribute and
associates the operation with a
UriTemplate as well as an underlying
transport verb that represents an
invocation (for example, HTTP POST,
PUT, or DELETE). The
WebInvokeAttribute attribute is a
passive operation behavior (the
IOperationBehavior methods do nothing)
that adds metadata to the operation
description. Applying the
WebInvokeAttribute attribute to a
service operation has no effect unless
a behavior that looks for this
metadata in the operation description
(such as WebHttpBehavior) is added to
the service's behavior collection. The
WebInvokeAttribute determines what
HTTP method that a service operation
responds to. By default, all methods
that have the WebInvokeAttribute
applied respond to POST requests.
Also further down the article defines how to map values to your service contract. Something like..
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "Mod?x={x}&y={y}")]
long Mod(long x, long y);
EDIT: To make this a bit more informative for people new to the field.
an intro into REST without going into platform specifics.
and a how to set up a simple REST style wcf service using wcf
I'm still learning about REST and, in my test, came up with this scenario I don't know how to deal with.
I have an existing sample WCF service which uses Linq-to-Sql. Its a tremendously simple database with a single table called "Tasks" which has four fields: Id, Description, IsCompleted, and EnteredDate. (I mentioned this because I have no data contracts defined in the service itself, it all comes from the Context created by Linq.)
Getting data was trivial to convert to REST... as was deleting data. However, inserting new records doesn't seem as easy.
My RPC-style contract operation looks like this:
[OperationContract]
void AddTask(string description);
The Id, IsCompleted, and EnteredDate are not needed as the service implementation looks like this:
public void AddTask(string description)
{
TaskListLinqDataContext db = new TaskListLinqDataContext();
Task task = new Task()
{ Description = description, IsCompleted = false,
EntryDate = DateTime.Now };
db.Tasks.InsertOnSubmit(task);
db.SubmitChanges();
}
The Id is an Identity and therefore handled by the database.
My first thought was to decorate the Operation contract like this:
[WebInvoke(Method="PUT", UriTemplate="tasks/{description}")]
[OperationContract]
void AddTask(string description);
But I don't really know how to get this to work. When I try using Fiddler to add this it returns a result of 411 (Length Required).
What would be the proper way to do this? Will I have to re-write the implementation to accept a whole XML document representing the new record?
Results:
I finally found a nice blog post that helped me resolve this. It turns out I was pretty much doing things correctly but I was putting the test into Fiddler improperly. I also added a few more details to my attribute.
[WebInvoke(RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
Method = "POST", UriTemplate = "tasks/{description}",
BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
void AddTask(string description);
When I put my Uri into Fiddler it needed to look like this:
http://ipv4.fiddler:8054/tasks/this+is+a+sample+desc+that+works
Now my service correctly accepts the data and can add the task to the database.
Take a look at the WCF REST Starter Kit, which can be downloaded from CodePlex here.
I think this pretty much describes how to add an item to a container in a restful way.
Depending on the requirements, you could simply enable regular CRUD via Astoria? I have a series covering how to do this with LINQ-to-SQL here. Just a thought.
If you want to do a RESTful web service then don't use a WCF application. Modify your URI template to something like Task/new and put the data of the new task in the body of the POST http request. I implement RESTful web services in ASP.NET as generic handlers (*.ashx). This allow me to ready the http method and go from there.
kevin
I am using a class in a C# ASP.NET project to allow a script written in some random scripting language to expose webservice methods dynamically - in other words, the script should be able to expose a method of any name with any signature (as long as it's valid, anyway) to the outside world through this SOAP interface (able to add and remove them at will, without needing a hard code change), and as such I need to be able to create a webservice class in C# while being able to dynamically add and remove methods at runtime.
Now, the best plan I've been able to come up with so far is (runtime) generating C# code to represent the webservice, using System.Reflection.Emit to compile it and then loading the assembly at runtime - all whenever the script adds or removes a method to/from the service (should not happen very often, mind).
Does anyone have a better idea than this?
You can modify WSDL by using SoapExtensionReflector class. From Kirk Evans Blog:
The SoapExtensionReflector is called when your type is being reflected over to provide the WSDL definition for your service. You can leverage this type to intercept the reflection call and modify the WSDL output.
The following example removes the first method out of 2 web service methods:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
[WebMethod]
public int Multiply(int a, int b)
{
return a * b;
}
}
Create a class inherited from SoapExtensionReflector:
namespace TestWebservice
{
public class MyReflector : SoapExtensionReflector
{
public override void ReflectMethod()
{
//no-op
}
public override void ReflectDescription()
{
ServiceDescription description = ReflectionContext.ServiceDescription;
if (description.PortTypes[0].Operations.Count == 2)
description.PortTypes[0].Operations.RemoveAt(0);
if (description.Messages.Count == 4)
{
description.Messages.RemoveAt(0);
description.Messages.RemoveAt(0);
}
foreach (Binding binding in description.Bindings)
{
if (binding.Operations.Count == 2)
binding.Operations.RemoveAt(0);
}
if (description.Types.Schemas[0].Items.Count == 4)
{
description.Types.Schemas[0].Items.RemoveAt(0);
description.Types.Schemas[0].Items.RemoveAt(0);
}
}
}
}
Add this to configuration/system.web section in web.config:
<webServices>
<soapExtensionReflectorTypes>
<add type="TestWebservice.MyReflector, TestWebservice" />
</soapExtensionReflectorTypes>
</webServices>
This should give you a starting point to dynamically removing methods from WSDL document. You would also need to throw NotImplementedException from web method if it is disabled.
Finally, you need to disable web service documentation produced by invoking .asmx endpoint without ?WSDL parameter. Set href attribute of wsdlHelpGenerator element to some URL. You can use DefaultWsdlHelpGenerator.aspx as a starting point for your own documentation handler. See question on web service documentation in XML Files, August 2002.
XMLRPC is fairly dead, isn't it?
SOAP implies a WSDL. How do you generate the WSDL dynamically?
You should look into using WCF. I expect you'll be able to take control of the process of generating the WSDL (and other metadata), yet you should also be able to take control of the processing of incoming messages. In particular, you will be able to examine the incoming messages to determine which script to run, what parameters to pass, etc.
You could create a WCF service with an input and output type of xs:any and handle the incoming request as a raw Message. That would allow you to accept any type of data and return any type of data. You would not use data contracts or static types, just a Message in and a Message out.
The problem with this approach is that generating a proxy from the WSDL really does nothing to help the consumer other than provide a wrapper to call the method. Providing data that is acceptable to the method would require hand-rolling data types, etc which is not that hard, it is just not as intuitive as a hard, typed contract.
Does it have to be a SOAP interface? That sounds like it might be more suitable to a route/REST/etc based API. You could do something in ASP.NET MVC (with a custom IController.Execute method that resolves the action to the method) pretty easily (in fact, I'm working on something very similar for some of my own code at the moment).
For example, you might have routes:
http://myserver/myservice/mymethod
that accepts (either in the body or args) the payload (parameters), and returns the result in the response. In non-MVC you should be able to do something similar with a wildcard-mapped generic handler.
Here is a suggestion:
Use WCF.
Create a WSDL from WCF using
information in the following blog
post:
http://www.pluralsight.com/community/blogs/kirillg/archive/2006/06/18/28380.aspx
You can then publish this information
using MEX.
The services are then open for your
clients to down load the meta data
and call the services.