I'm writing a SOAP consumer using WCF.
In the following WCF service contract, WCF expects that the response has a Body and an element called HelloResponse:
[ServiceContract]
public interface HelloService
{
string Hello(string input);
}
On the service I'm calling, it is actually called HelloResult. How can I tell WCF this, without using MessageContracts? I tried combinations and variations of the following, but without success.
...
[OperationContract(ReplyAction = "HelloResult")]
[return: MessageParameter(Name = "HelloResult")]
...
If you know the service operation Hello(string) returns a string then why not just create a channel and call the operation directly rather than worrying about messages?
Related
I have a stock WCF Rest application (default Web.config, Web Routing). I am unable to get the WCF framework to auto de-serialize the request stream into typed objects. I have a service with a method sig in the form...
[WebInvoke(Method = "POST",
UriTemplate = "",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json)]
MethodA(FirstParam first, SecondParam second)
If I initiate a request from fiddler or jQuery using $.ajax I get a 400 Bad Request error. I've done plenty of searching and found that changing the method sig to use a System.IO.Stream allows the method to be executed, however it also adds the overhead of de-serializing the objects.
The raw request body is as follows
{
"first":"{\"p1\":\"p1 value\",\"p2\":\"p2 value\",\"p3\":100\"p4\":null}",
"second":"{\"p1\":\"p1 value\"}"
}
Yeh the application doesn't even break into the service itself unless the method has either a Stream, or no arguments. There is only 1 post method in this service, the other is a GET method which is working correctly.
I've used http://www.codeproject.com/KB/ajax/jQueryWCFRest.aspx as a reference implementation, but have been unable to get it to work on this solution.
Is there something that I'm missing here that hopefully someone else can see?
Leon
Bleh... the problem turned out to be the way the request was serializing values!
{
"first":"{\"p1\":\"p1 value\",\"p2\":\"p2 value\",\"p3\":100\"p4\":null}",
"second":"{\"p1\":\"p1 value\"}"
}
Should have been without the escaped quotes....
{
"first":"{"p1":"p1 value","p2":"p2 value","p3":100"p4":null}",
"second":"{"p1":"p1 value"}"
}
The reason this was happening was JSON.stringify was being called not only on the wrapped request parameters, but on each parameter as well.
I have some problems with mocking WCF services:
1) I declare a class with empty methods which only implements my service interface:
public class MyFakeService : IMyService {
...
public virtual MyResult GetResult(MyResponse response){
throw new NotImplementedException();
};
}
2) I have the MyResponse class:
public class MyResponse {
public long myField;
}
3) I create a mock of the service class and a service host to host this fake service:
myFakeService = mocks.StrictMock<MyFakeService>();
ServiceHost host = new ServiceHost(myFakeService);
(here I have ommited the endpoint configuration etc.)
4) And now I try to test my client. The client.GetSomethingFromService() method exactly calls the GetResult(MyResponse) method of the service.
With.Mocks(mocks)
.Expecting(() => Expect
.Call(myFakeService.GetResult(null))
.IgnoreArguments()
.Constraints(PublicField.Value("myField", 777))
.Return(new MyResult()))
.Verify(() => myClient.GetSomethingFromService());
The issue is that if something wrong in the service, I can only see something like this:
System.ServiceModel.CommunicationObjectFaultedException:
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used
for communication because it is in the Faulted state.
How do I know what exactly wrong? Maybe arguments constraints verification failed or something else...?
Thanks.
Firstly, avoid using strict mocks. They're a bad practice because they make your tests too brittle.
Secondly if you're testing a WCF service you don't need to spin up a ServiceHost since you'll then be doing an integration test. You're just wanting to test the logic of your service, not the WCF infrastructure.
For a run through of how to use RhinoMocks and WCF services have a look at my blog post on unit testing WCF services
My application is accessing a WCF service hosted at the server.
When i try to call a Method with [WebInvoke] attribute the response returned is always "error".
All other methods with [WebGet] attribute are working fine.
The interface as in the reference.cs is
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="SyncService.IService")]
public interface IService
{
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="")]
[System.ServiceModel.FaultContractAttribute(typeof(DataSynchronization.SyncService.WebExceptionDetail), Action="Update", Name="WebExceptionDetail", Namespace="http://schemas.datacontract.org/xxx.WebServices")]
string Update(string mode, string data);
}
whenever i try to call the Update method of the service using the code
string response = objClient.Update("manual", string data);
the response obtained is "Error".and the log displays
Error -
"System.Xml.Schema.XmlSchemaValidationException:
The element 'providers' cannot contain
text. List of possible elements
expected: 'provider'". on calling
Update
The service is hosted in a remote server which i cannot debug either.
I have a service exposed as WCF via NServiceBus. Ultimately, I'd like to call to this service from silverlight. My WCF Service Interface looks like this:
[ServiceContract]
public interface ISettingsService
{
[OperationContract(Action = "http://tempuri.org/IWcfServiceOf_RequestSettingsMessage_SettingsResponseMessage/Process", ReplyAction = "http://tempuri.org/IWcfServiceOf_RequestSettingsMessage_SettingsResponseMessage/ProcessResponse") ]
SettingsResponseMessage FetchSettings(RequestSettingsMessage request);
}
My NSB WCF service is defined as:
public class CoreService : WcfService<RequestSettingsMessage, SettingsResponseMessage>
{
}
When I invoke the FetchSettings method on the service, I get an exception:
System.TypeInitializationException: The type initializer for 'NServiceBus.WcfSer
vice`2' threw an exception. ----> System.InvalidOperationException: Centerlink.Services.Core.Msg.Settings.SettingsResponseMessage must be an enum representing error codes returned by the server.
It seems that the WcfService<> class is restricting the return type of a WCF method to be an enum. How can I have my service return something other than an enum? Do I need to create a custom implementation of NServiceBus.WcfService<>?
You need to create your own wcf service for that scenario.
More details here:
http://tech.groups.yahoo.com/group/nservicebus/message/6295
In order to support streaming i return Message with override to OnWriteBody...
The problem is if an exception is thrown in the OnWriteBody (DB timeout or whichever)
The ProvideFault in the IErrorHandler is not called and therefore i have no way to propagate the error to the client( via a filtering in the IErrorHandler).
Is there a way to solve this.
Thanks.
when doing streaming with WCF I create two ServiceContracts one that does the streaming another that will send the notification at the end of the streaming.
The response ServiceContract I use a duplex type binding. The client as to call the response ServiceContract first to get a ticket for its transaction then call my transfer ServiceContract. Then at the end of the transaction the client will get notified of success or failure from the response ServiceContract.
[ServiceContract]
public interface IStreamFileService
{
[OperationContract]
void Upload(Stream stream);
}
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ITransferCallback))]
public interface IStreamFileResponseService
{
[OperationContract(IsOneWay = false, IsInitiating = true, IsTerminating = false)]
Guid StartUpload();
}
[ServiceContract]
public interface ITransferCallback
{
[OperationContract]
void OperationComplete(ResponseMessage response);
}
I do this in two services because my requirements and workflow requires me to track many things and do authentication, validation, etc.
OnWriteBody is called when response headers, like 200 was already sent to client. There for is impossible to handle errors in this stage.
Two workaround/tricks I've used:
Wait for first data-row before sending 200(like before returning Message) and iterate further rows inside OnWriteBody. This will work for because most of SQL Errors and Timeouts occurs before showing any data. Still, not cover cases when error appears while result-set iteration.
Have special error handling code on client and server. Like, in case of error server inside OnWriteBody may serialize error and send it as special Data-Row. Client should expect such special Data-Row while receiving response and handle accordingly.