I have a WCF service implemented via custom wsdl. It simple have 5 methods as per wsdl. Call to My service from standard client works fine. Problem was in some old implementation which send SoapAction=""
I wanted to change the soapAction to some value if i got empty. For that I have implemented CustomBehavior but even in it I can't able to hit AfterReceiveRequest method or any method in the behavior
public class CustomInspectorBehavior : Attribute, IDispatchMessageInspector,
IClientMessageInspector, IEndpointBehavior, IServiceBehavior
Any idea i can response even if i have SOAPAction="" in the request
Edit
My Service Looks like following
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://txnTest.Test.com", ConfigurationName="MyServiceTxnHost")]
public interface IMyServiceTxnHost
{
[System.ServiceModel.OperationContractAttribute(Action = "http://txnTest.Test.com/IMyServiceTxnHost/payment")]
//[System.ServiceModel.OperationContractAttribute(Action = "*")]
//[System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]
paymentResponse payment(paymentRequest request);
//[System.ServiceModel.OperationContractAttribute(Action = "*")]
[System.ServiceModel.OperationContractAttribute(Action = "http://txnTest.Test.com/IMyServiceTxnHost/commit")]
//[System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]
commitResponse commit(commitRequest request);
//[System.ServiceModel.OperationContractAttribute(Action = "*")]
[System.ServiceModel.OperationContractAttribute(Action = "http://txnTest.Test.com/IMyServiceTxnHost/reserve")]
//[System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]
reserveResponse reserve(reserveRequest request);
//[System.ServiceModel.OperationContractAttribute(Action = "*")]
[System.ServiceModel.OperationContractAttribute(Action = "http://txnTest.Test.com/IMyServiceTxnHost/cancel")]
//[System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]
cancelResponse cancel(cancelRequest request);
//[System.ServiceModel.OperationContractAttribute(Action = "*")]
[System.ServiceModel.OperationContractAttribute(Action = "http://txnTest.Test.com/IMyServiceTxnHost/raise")]
//[System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]
raiseResponse raise(raiseRequest request);
//[System.ServiceModel.OperationContractAttribute(Action = "*")]
[System.ServiceModel.OperationContractAttribute(Action = "http://txnTest.Test.com/IMyServiceTxnHost/balance")]
//[System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]
balanceResponse balance(balanceRequest request);
}
Set OperationContract's property Action to "*" to associate every call which cannot reach its destination with specific method.
[OperationContract(Action = "*")]
void LostRequest();
Related
I used XSD2Code to generate C# code from given XSD. This tool generated code snipped as below:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Orders
{
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public int OrderID {get;set;}
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 1)]
public string Description {get;set;}
}
Coud some one please guide me with following queires, please
If I leave the above code as it is, does WCF serializes the above class?
Currently I'm getting this error on wcf test client: ""this Operation is not
supported in WCF Test Client".
Do I need to add DataContract and DataMember on top of the above generated codes?
Which option is beter between DataContract Serializer vs XML Serializer
Thanks you.
It should work, as long as the contract (either the service contract interface or the operation contract method which uses this type) is marked with the [XmlSerializerFormat] attribute
No - if you decorate the contract with [XmlSerializerFormat], the DataContract/DataMember attributes are ignored (the XML serialization attributes, like the ones in this type, are used instead)
The XmlSerializer allows you to completely control the XML in which the types are serialized; the DataContractSerializer (DCS) doesn't (it's more limited). But the DCS has a better performance, so which one is better really depends on your scenario.
The code below shows a service which uses this type, and it works fine, even with the WcfTestClient.
public class StackOverflow_7155154
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Orders
{
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public int OrderID { get; set; }
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 1)]
public string Description { get; set; }
}
[ServiceContract]
[XmlSerializerFormat]
public interface ITest
{
[OperationContract]
Orders GetOrders();
}
public class Service : ITest
{
public Orders GetOrders()
{
return new Orders { Description = "My order", OrderID = 1 };
}
}
public static void Test()
{
//MemoryStream ms = new MemoryStream();
//XmlSerializer xs = new XmlSerializer(typeof(Orders));
//Orders o = new Orders { OrderID = 1, Description = "My order" };
//xs.Serialize(ms, o);
//Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.GetOrders());
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
I have written a WCf Service which has a Collection type input body parameter and another parameter as query string as following:
[WebInvoke(Method = "PUT", UriTemplate = "users/role/{userID}",BodyStyle=WebMessageBodyStyle.WrappedRequest)]
[OperationContract]
public bool AssignUserRole(int userID,Collection<int> roleIDs)
{
//do something
return restult;
}
Now when I am trying to pass this parameter I am getting de serializing error. I have tried following format:
<AssignUserRole xmlns="http://tempuri.org/">
<roleIDs>
<roleID>7</roleID>
</roleIDs>
</AssignUserRole>
<AssignUserRole xmlns="http://tempuri.org/">
<ArrayOfroleID>
<roleID>7</roleID>
</ArrayOfroleID>
</AssignUserRole>
<AssignUserRole xmlns="http://tempuri.org/">
<ArrayOfint>
<int>7</int>
</ArrayOfint>
</AssignUserRole>
Can some one help me how can I pass this Array(Collection type Body parameter)?
Thanks.
The correct format would be this:
<AssignUserRole xmlns="http://tempuri.org/">
<roleIDs xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:int>7</a:int>
<a:int>8</a:int>
</roleIDs>
</AssignUserRole>
One easy way to find out what the expected format is for a certain operation is to use a WCF client with the same contract, send a message with it and look at the operation using Fiddler. The program below does that.
public class StackOverflow_6339286
{
[ServiceContract]
public interface ITest
{
[WebInvoke(Method = "PUT", UriTemplate = "users/role/{userID}", BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[OperationContract]
bool AssignUserRole(string userID, Collection<int> roleIDs);
}
public class Service : ITest
{
public bool AssignUserRole(string userID, Collection<int> roleIDs)
{
return true;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
WebChannelFactory<ITest> factory = new WebChannelFactory<ITest>(new Uri(baseAddress));
ITest proxy = factory.CreateChannel();
proxy.AssignUserRole("1234", new Collection<int> { 1, 2, 3, 4 });
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
Also notice that there's a problem in your UriTemplate: the path variable {userId} cannot be of type int (it must be a string). This is fixed in the sample code above.
One more thing: if you don't want to use the default namespace for collections / arrays, you can use a [CollectionDataContract] class to change it. If instead of using Collection you used the class below, then the first body you tried should work:
[CollectionDataContract(Namespace = "http://tempuri.org/", ItemName = "roleID")]
public class MyCollection : Collection<int> { }
When I make a standard Get Request call to a restful wcf service it returns with a content type of "application/xml". A vendor is asking we send with a content type of "text/xml". How do I switch this in wcf? Is it an attribute?
The call is this:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, Namespace = "")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document, Use=OperationFormatUse.Literal)]
public class Player
{
[WebGet(UriTemplate = "{id}")]
public string GetTestDetailsRequest(string id)
{
TestService.TestServiceClient testServiceClient = new TestServiceClient();
string xml = testServiceClient.GetTestDetailsRequest(Guid.Parse(id));
return xml;
}
}
Don't try and use WCF to call RESTful services. Just use HttpWebRequest or HttpClient, that way you will have control over your request.
You can override the content type:
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
I have written a WCF REST Service as follows
namespace UserService
{
// TODO: Modify the service behavior settings (instancing, concurrency etc) based on the service's requirements. Use ConcurrencyMode.Multiple if your service implementation
// is thread-safe.
// TODO: Please set IncludeExceptionDetailInFaults to false in production environments
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceContract]
public class Service
{
UserManager userManager = new UserManager();
[OperationContract]
[WebGet(UriTemplate = "{userName}")]
[WebHelp(Comment = "Gets an user object given the username")]
public User GetUser(string userName)
{
return userManager.Read(userName);
}
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "", RequestFormat=WebMessageFormat.Xml, ResponseFormat=WebMessageFormat.Xml, BodyStyle=WebMessageBodyStyle.Bare)]
[WebHelp(Comment = "Creates an User")]
public void CreateUser(User user)
{
userManager.Create(user);
}
}
}
I am accessing this from my ASP.NET application as follows.
HttpClient client = new HttpClient();
HttpContent content = null;
DiscussionForum.Library.User user = new User();
user.UserEmailAddress = emailAddressTextBox.Text;
user.UserName = userNameTextBox.Text;
user.UserPassword = passwordTextBox.Text;
content = HttpContentExtensions.CreateXmlSerializable<DiscussionForum.Library.User>(user);
content.LoadIntoBuffer();
HttpResponseMessage response = client.Post(new Uri("http://localhost/UserService/Service.svc"),"application/xml", content);
Response.Write(response.StatusCode.ToString());
I am getting a Badrequest 400 in the status code on the client side.
Am I missing something?
Well, one thing I immediately see is that your service uses the DataContractSerializer and your client uses the XmlSerializer, and so the XML representations of the "User" type probably aren't the same.
Either use the [XmlSerializerFormat] attribute on the service, or use HttpContentExtensions.CreateDataContract on the client (but not both of course :)
But I'm not 100% sure that this is your problem (or the only problem)... If it's not, reply here and I can help with some debugging tips.
I have a WCF service hosted in a Windows service.
I've added to it a webHttpBinding with a webHttp behaviour and whenever I send it a GET request I get http 200 which is what I want, problem is I get an http 405 whenever I send it a HEAD request.
Is there a way to make it return http 200 also for HEAD?
Is that even possible?
edit: that's the operation contract:
[OperationContract]
[WebGet(UriTemplate = "MyUri")]
Stream MyContract();
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet(UriTemplate="/data")]
string GetData();
}
public class Service : IService
{
#region IService Members
public string GetData()
{
return "Hello";
}
#endregion
}
public class Program
{
static void Main(string[] args)
{
WebHttpBinding binding = new WebHttpBinding();
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri("http://localhost:9876/MyService"));
host.AddServiceEndpoint(typeof(IService), binding, "http://localhost:9876/MyService");
host.Open();
Console.Read();
}
}
The above code works fine. I get a 405 (Method not allowed) on HEAD request. The version of assembly I am using is System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35.
Actually as far as I know there is no straight forward way of allowing it.However you could try something like the solution below..But this has to be done for each method that needs GET and HEAD, which makes it a not so elegant solution..
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "*", UriTemplate = "/data")]
string GetData();
}
public class Service : IService
{
#region IService Members
public string GetData()
{
HttpRequestMessageProperty request =
System.ServiceModel.OperationContext.Current.IncomingMessageProperties["httpRequest"] as HttpRequestMessageProperty;
if (request != null)
{
if (request.Method != "GET" || request.Method != "HEAD")
{
//Return a 405 here.
}
}
return "Hello";
}
#endregion
}
Sounds like a serious bug in the service (or even the framework). Support for HEAD in HTTP/1.1 is in no way optional.