I want to wrap each result from one Wcf service in my application in something like
public class OperationResult{
public string Status;
public string Data;
}
even if my contract looks like
[ServiceContract]
internal interface ITest
{
[OperationContract,
WebGet(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
MyDc EchoDc(MyDc input);
}
From what I've read the potential extensibility points are IServiceBehavior, IEndpointBehavior, IContractBehavior, IOperationBehavior.
Any thoughts where I can hook my wrapping magic ?
Look # my answer here:
How to customize the process employed by WCF when serializing contract method arguments?
There it is mentioned how you can replace an object of one type to another type while it is being returned.
I think thats not possible via extensionpoints on the WCF framework because what you watn to do is to change your contract.
The contract is a c# interface which is used by your client.
You have to write an own proxy class for use by your client where you can map the operation results to whatever you like:
class ServiceProxy : ClientBase<YourServiceInterface>
{
public OperationResult EchoDc(MyDs input)
{
MyDc result = Channel.EchoDc(input);
return new OperationResult( ... // map your operation result here))
}
}
Related
Is it a good idea to get the current WCF behavior withing a WCF operation contract and do some stuff depending on the current behavior?
If no: Why not?
If yes: How can I do that?
For example something like this:
// Interface
[ServiceContract]
public interface IDataService
{
[OperationContract]
DataResponse GetData(DataRequest request);
}
// Implementation of the IDataService.GetData
public DataResponse GetData(DataRequest request)
{
// get current behavior
IBehavior currBevhavior = ...?
if (currBehavior.name = ""){
// custom code for this behavior
}
...
}
Edit: The same thing for the binding: Is it a good idea to do stuff in code depending on which binding the current request came in? How can I do that?
I'm wondering about the behind the scenes magic that's happening when you create a WCF-Web service.
In one old project I got methods that I can call from JavaScript that look like this
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
IEnumerable<Result> SearchObjects(string x, int y, double z);
And this works when I send { "x": "something", "y": 1, "z": 1.5 } from JavaScript.
A couple of months after the creation of that webservice, I found the WCF Web API and tried to make something similar.
Difference was that I created the route in my Global.asax with the HttpServiceHostFactory()
Now when I try to call the method, I get an exception like this
Exception Details: System.InvalidOperationException:
The HttpOperationHandlerFactory is unable to determine the input parameter that should be associated with the request message content for service operation 'Invoke_LoginRequest'. If the operation does not expect content in the request message use the HTTP GET method with the operation. Otherwise, ensure that one input parameter either has it's IsContentParameter property set to 'True' or is a type that is assignable to one of the following: HttpContent, ObjectContent1, HttpRequestMessage or HttpRequestMessage1.
And to get it to work, I need to declare the method like this (VB.Net)
Public Function Invoke_LoginRequest(ByVal request As HttpRequestMessage(Of JsonValue)) As HttpResponseMessage(Of String)
But then I need to parse the JsonValue manually. So how does the old version really work? And is there any way I could get that behaviour back?
Best regards
Jesper
1) Define a class containing the data that you want to receive, i.e,
public class Model
{
public string x { get; set; }
public int y { get; set; }
public double z { get; set; }
}
2) Define the operation parameter as an ObjectContent<Model>
public HttpResponseMessage Post(ObjectContent<Model> c){
Model m = c.ReadAs();
...
}
HTH
Pedro
I've got a WCF-hosted service right now which is self-hosted and defined like this:
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, Method = "PUT", UriTemplate = "/device")]
void updateDeviceLevel(ZDevice device);
The ZDevice class looks like this:
public class ZDevice {
public bool? newPowerState { get; set; }
public int nodeId {get; set;}
}
I have a simple Mac client which consumes the service by using an http post. It posts {"newLevel":27,"nodeId":6} to the \devices url and .NET magically stuffs the values into a ZDevice object for me. All is well here.
Now however, I need to add some basic security to the mix. I've done this by adding a new parameter and some "RequestWrapping" to the method call:
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, BodyStyle=WebMessageBodyStyle.WrappedRequest, Method = "PUT", UriTemplate = "/device")]
void updateDeviceLevel(string password, ZDevice device);
What I'm trying to do now is figure out what syntax the server is expecting from the consuming clients. I'd hoped that posting in {"password":"somepwd", "newLevel":27,"nodeId":6} would work, but .NET is no longer able to "deserialize" that into the ZDevice object like it did before.
Anyone got some suggestions for me?
Thanks
It should look like this:
{"password":"somepwd", "device": {"newLevel":27,"nodeId":6}}
Each property on the JSON object has a value; and in the case of device it's just a new object.
Note that in your ZDevice class you called it newPowerState, but in JSON you are calling it newLevel. In your class it's also a bool, but in JSON you are assigning it an int. Something isn't matching up.
Based on your C#, I'd expect it to look like this:
{"password":"somepwd", "device": {"newPowerState":true,"nodeId":6}}
The property names in your JSON object should match the parameter / property names in C#.
I have two ServiceContracts implemented as interfaces. I want to export the metadata for only one of them. The trick is that both interfaces are implemented by the same class. Therefore, I don't think that I can use /excludeTypes. Please include example syntax when answering. Thanks!
EDIT: A co-worker recently asked me why this is necessary. The reason why is that the first ServiceContract is for a REST service, which it doesn't make sense to export metadata for. So I get two wsdl and xsd files generated, distinguishable only because the second filename is appended with "1". This makes tooling difficult, and adds more clutter to the output directory.
I've added a bounty to try and generate interest in this question.
I created a Service Contract class implementing 2 Interfaces like you described.
namespace NS
{
[ServiceContract]
public interface IREST
{
[OperationContract]
string WorldHello(string name);
}
[ServiceContract]
public interface IInterface
{
[OperationContract]
string HelloWorld(string name);
}
public class CI2 : IREST, IInterface
{
public string WorldHello(string name)
{
return "World Hello: " + name;
}
public string HelloWorld(string name)
{
return "Hello World: " + name;
}
}
}
when running svcutil normally, I get a wsdl with methods from the 2 interfaces
when I run svcutil with /excludeType:IREST for example, I get only IInterface methods.
svcutil /excludeType:NS.IREST ci2service.exe
are you using the same configuration? In that case /excludeType works.
Given a contract such as:
[ServiceContract] public interface IService
{
[OperationContract]
[WebGet(UriTemplate = "GetData/{id}.{format}")]
ResponseData GetData(string id, string format);
}
Is there a way to get the service to respond with json when requested as:
/GetData/1234.json, xml when requested as /GetData/1234.xml and still be available as a proper soap service at some other url, with a strongly typed wsdl contract?
Using a Stream as the return value for GetData is not workable, as though it fufills the first two requirements, wcf can't create a full wsdl specification as it has no idea what the contents of the resultant Stream will be.
You should have two separate methods which take id and format (and they would call a shared implementation that returns ResponseData) which have different WebGet attributes:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet(UriTemplate = "GetData/{id}.{format}.xml",
ResponseFormat=WebMessageFormat.Xml)]
ResponseData GetDataXml(string id, string format);
[OperationContract]
[WebGet(UriTemplate = "GetData/{id}.{format}.json",
ResponseFormat=WebMessageFormat.Json)]
ResponseData GetDataJson(string id, string format);
}
For the SOAP endpoint, you should be able to call either method, but you are going to have to have a separate ServiceHost instance hosting the implementation of the contract.