I'm trying to use the PushSubscription feature of Exchange 2010. So far I've got the code to setup push on Exchange 2010:
ExchangeService esService = new ExchangeService();
esService.Credentials = new WebCredentials("user", "pass", "domain");
esService.Url = new Uri("https://exchange-box-2010/ews/exchange.asmx");
PushSubscription ps = esService.SubscribeToPushNotificationsOnAllFolders(new Uri("http://192.168.1.102:8080/FinWorkFlow"), 1, null, EventType.NewMail, EventType.Copied);
I've also got a WCF service that run's at http://192.168.1.102:80/FinWorkFlow with a tcp tracing utility redirecting from 8080 to 80. The traces indicate that Exchange sends out a request to http://192.168.1.102:8080/FinWorkFlow and that a good response is sent from my WCF service. However the SendNotificationResponseType parameter of the SendNotification method is always null:
SendNotificationResultType INotificationServiceBinding.SendNotification(SendNotificationResponseType request)
{
if(request != null && request.ResponseMessages != null)
{
foreach(ResponseMessageType messsage in request.ResponseMessages.Items)
{
if(messsage.ResponseCode != ResponseCodeType.NoError)
{
return CreateNotificationResult(SubscriptionStatusType.Unsubscribe);
}
SendNotificationResponseMessageType mtNotificationMessage = (SendNotificationResponseMessageType)messsage;
NotificationType ntNotification = mtNotificationMessage.Notification;
string strSubscriptionId = ntNotification.SubscriptionId;
for(int i = 0; i < ntNotification.Items.Length; i++)
{
if(ntNotification.ItemsElementName[i].ToString() == "NewMailEvent")
{
BaseObjectChangedEventType bocet = (BaseObjectChangedEventType)ntNotification.Items[i];
}
}
}
}
return CreateNotificationResult(SubscriptionStatusType.OK);
}
The interface is defined as:
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42")]
[System.Web.Services.WebServiceBindingAttribute(Name = "NotificationServiceBinding", Namespace = "http://schemas.microsoft.com/exchange/services/2006/messages")]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(ServiceConfiguration))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(DirectoryEntryType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(TargetFolderIdType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(RecurrenceRangeBaseType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(RecurrencePatternBaseType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(AttachmentType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BasePermissionType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseItemIdType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseEmailAddressType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseFolderIdType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseFolderType))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(BaseResponseMessageType))]
[ServiceContract(Namespace = "http://schemas.microsoft.com/exchange/services/2006/messages", ConfigurationName = "Microsoft.Exchange.Notifications.INotificationServicePortType")]
public interface INotificationServiceBinding
{
/// <remarks/>
[OperationContract(Action = "*", ReplyAction = "*")]
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/exchange/services/2006/messages/SendNotification", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Bare)]
[return: System.Xml.Serialization.XmlElementAttribute(Namespace = "http://schemas.microsoft.com/exchange/services/2006/messages")]
SendNotificationResultType SendNotification([System.Xml.Serialization.XmlElementAttribute("SendNotification", Namespace = "http://schemas.microsoft.com/exchange/services/2006/messages")] SendNotificationResponseType SendNotification1);
}
A typical request from Exchange is:
POST /FinWorkFlow HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
SOAPAction: http://schemas.microsoft.com/exchange/services/2006/messages/SendNotification
Host: 192.168.1.102:8080
Content-Length: 1486
Connection: Close
<?xml version="1.0" encoding="utf-8"?><soap11:Envelope xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"><soap11:Header><RequestServerVersion xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" Version="Exchange2010" /></soap11:Header><soap11:Body><m:SendNotification xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"><m:ResponseMessages><m:SendNotificationResponseMessage ResponseClass="Success"><m:ResponseCode>NoError</m:ResponseCode><m:Notification><t:SubscriptionId>EgBiZnQtbWVybGluLnJibS5sYW4QAAAAz4lScRmxbEaLeCfsAFRDmEswGeTtJs0I</t:SubscriptionId><t:PreviousWatermark>AQAAAOUSjqlc3mdHh1LhIiuqSBc1UCgAAAAAAAA=</t:PreviousWatermark><t:MoreEvents>false</t:MoreEvents><t:NewMailEvent><t:Watermark>AQAAAOUSjqlc3mdHh1LhIiuqSBc8UCgAAAAAAAE=</t:Watermark><t:TimeStamp>2010-09-20T15:16:28Z</t:TimeStamp><t:ItemId Id="AAMkAGVmOWI3OGE5LWJmMjEtNDU4Mi1hY2JlLTdhYzZmMGQ2N2Q4ZABGAAAAAACd5Nq062e3ToqPr4+g8e/UBwDjUS8vlMohRaUyr3p641BAACy83CEfAABwOzEV48hOQJYkk18qYDCqAAAAnG3SAAA=" ChangeKey="CQAAAA==" /><t:ParentFolderId Id="AAMkAGVmOWI3OGE5LWJmMjEtNDU4Mi1hY2JlLTdhYzZmMGQ2N2Q4ZAAuAAAAAACd5Nq062e3ToqPr4+g8e/UAQDjUS8vlMohRaUyr3p641BAACy83CEfAAA=" ChangeKey="AQAAAA==" /></t:NewMailEvent></m:Notification></m:SendNotificationResponseMessage></m:ResponseMessages></m:SendNotification></soap11:Body></soap11:Envelope>
Can anyone explain why the body of the SOAP request is not being picked up and put into the SendNotificationResponseType variable?
Finally figured it out!
Turns out that I used the wsdl tool to build the interface - should have used svcutil. This built an interface with the correct method attributes.
Related
I'm have a problem with a SOAP header created in my C# client. The server is sending back the error
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<s:Header xmlns:s="http://www.w3.org/2003/05/soap-envelope" />
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:MustUnderstand</soap:Value>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="en">MustUnderstand headers: [{http://www.w3.org/2005/08/addressing}To] are not understood.</soap:Text>
</soap:Reason>
</soap:Fault>
</soap:Body>
</soap:Envelope>
I have been under the impression that I have been removing all SOAP headers with the following code.
internal class CustomMessageInspector : IEndpointBehavior, IClientMessageInspector
{
public object BeforeSendRequest( ref Message request, IClientChannel channel )
{
request.Headers.Clear();
return null;
}
...
}
However, after activating System.ServiceModel.MessageLogging in the app.config, (WCF - Inspect the messages being sent/received?), I see that the server is correct - lo and behold there is a "To" header with "mustUnderstand" set to 1 :
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:To s:mustUnderstand="1">https://ws-single-transactions-int-bp.nmvs.eu:8443/WS_SINGLE_TRANSACTIONS_V1/SinglePackServiceV30</a:To>
</s:Header>
Any thoughts how I can prevent this header from being added?
Many thanks.
In case it helps anybody else, I have found a solution. In fact Nicolas Giannone provided all the necessary code here WSHttpBinding in .NetStandard or .NET core . What we can do is to replace the WSHttpBinding with a custom binding based on the WSHttpBinding, and then replace the TextMessageEncodingBindingElement with one with no addressing. Here's the code :
string endPoint = myConfig.SinglePackServicesEndPoint;
//Defines a secure binding with certificate authentication
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
// create a new binding based on the existing binding
var customTransportSecurityBinding = new CustomBinding( binding );
// locate the TextMessageEncodingBindingElement - that's the party guilty of the inclusion of the "To"
var ele = customTransportSecurityBinding.Elements.FirstOrDefault( x=>x is TextMessageEncodingBindingElement );
if( ele != null )
{
// and replace it with a version with no addressing
// replace {Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing)}
// with {Soap12 (http://www.w3.org/2003/05/soap-envelope) AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)}
int index = customTransportSecurityBinding.Elements.IndexOf( ele );
var textBindingElement = new TextMessageEncodingBindingElement
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
};
customTransportSecurityBinding.Elements[index] = textBindingElement;
}
I have a problem that given 3rd party WSDL I am able from a Console App to easily create a service proxy that works, but from a WF4 WF service I am not. The generated proxy in the latter case is clearly buggy, involving specifically 2 problems:
a) Message contracts always generated when not requested or needed
b) Incorrect response messages and xml wrapper names used, resulting in null response objects and failed deserialization
The problem I am facing is in the actual generation of the Reference.cs class on the basis of 3rd party WSDL. In the WSDL there are many operations, and in order of appearance 2 of them are as so:
<operation name="pu013">
<documentation>
<description>Check-response service</description>
<help>The service handles (cut out)</help>
</documentation>
<input message="tns:pu013Request" />
<output message="tns:SimpleResponse" />
</operation>
...
<operation name="mi102">
<documentation>
<description>Instruction insert to Matching System</description>
<help>This service (cut out)</help>
</documentation>
<input message="tns:mi102Request" />
<output message="tns:SimpleResponse" />
</operation>
What this results in in the Reference.cs is the following C#:
WorkflowService1.PSE.pu013Response pu013(WorkflowService1.PSE.pu013Request request);
...
WorkflowService1.PSE.pu013Response mi102(WorkflowService1.PSE.mi102Request request);
Note that for some reason the mi102 operation is generated with the INCORRECT response message of pu013Response, which is declared as this:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="pu013Response", WrapperNamespace="http://pse/", IsWrapped=true)]
public partial class pu013Response {
Note the WrapperName prevents the XML serializer from recognising the response, which is mi102Response, so for all operations that are not pu013 I always get a NULL response.
Also, this does NOT occur if I add a reference from a console application. This does not generate Message contracts, and in this case, invocation and response work.
What is different? Is svcutil being invoke behind the scenes? If so, what is different about the parameters used? Can svcutil be used to generate the xamlx activities too, so that I might find a command line workaround?
This looks like a VS / Add Service Reference bug. The alternative is to manually correct many operations in the Reference.cs.
Ideally, I am looking for a way to easily, automatically, run svcutil or Add Service Reference so that the Reference class is correct and the xamlx activities generated. A nice to have is an explanation of why there is a difference, and behind the scenes what is happening.
UPDATE:
Message contracts generated in the console app result in the same problem - incorrect Response declarations. The problem goes away if parameters are used instead of messages, which are not available from a WF service app.
I am far from an authority on these issues, and while this response below might not be an exact fit to your problem, my recent experience of making a proxyless connection to a service might offer some insight to you or the next person with a similar issue.
I would start by seeing if you can hand roll the SOAP request using fiddler, and see if you are able to create the correct message and send that along. Since you describe the automation tools as being buggy (or perhaps there is a config issue you're not getting just so). Either way, having a clear understanding of the shape of the contract, and being able to perform a reliable test in fiddler may offer clarity.
You don't necessarily need to rely on using a proxy. You can create your own soap message and send it along one of two ways. The first is using the ChannelFactory.
Create your message body (if required, message class can work w/out one)
Create your message
Send your message via the ChannelFactory
For step 1 you can construct your message by making a simple POCO to mirror what is expected in your contract. You should be able to derive what that class is via the WSDL.
Let's say the service is something like this:
[ServiceContract(Namespace = "http://Foo.bar.car")]
public interface IPolicyService
{
[OperationContract]
PolicyResponse GetPolicyData(PolicyRequest request);
}
public class PolicyData : IPolicyService
{
public PolicyResponse GetPolicyData(PolicyRequest request)
{
var polNbr = request.REQ_POL_NBR;
return GetMyData(polNbr);
}
}
You would need a class something like this:
[DataContract(Namespace = "http://Foo.bar.car")]
public class GetPolicyData
{
[DataMember]
public request request { get; set; }
}
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/Foo.bar.car.Model.Policy")]
public class request
{
///<summary>
/// Define request parameter for SOAP API to retrieve selective Policy level data
/// </summary>
[DataMember]
public string REQ_POL_NBR { get; set; }
}
and then you would call it like this:
private static Message SendMessage(string id)
{
var body = new GetPolicyData {request = new request{ REQ_POL_NBR = id }};
var message = Message.CreateMessage(MessageVersion.Soap11, "http://Foo.bar.car/IPolicyService/GetPolicyData", body);
// these headers would probably not be required, but added for completeness
message.Headers.Add(MessageHeader.CreateHeader("Accept-Header", string.Empty, "application/xml+"));
message.Headers.Add(MessageHeader.CreateHeader("Content-Type", string.Empty, "text/xml"));
message.Headers.Add(MessageHeader.CreateHeader("FromSender", string.Empty, "DispatchMessage"));
message.Headers.To = new System.Uri(#"http://localhost:5050/PolicyService.svc");
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
MessageEncoding = WSMessageEncoding.Text,
MaxReceivedMessageSize = int.MaxValue,
SendTimeout = new TimeSpan(1, 0, 0),
ReaderQuotas = { MaxStringContentLength = int.MaxValue, MaxArrayLength = int.MaxValue, MaxDepth = int.MaxValue }
};
message.Properties.Add("Content-Type", "text/xml; charset=utf-8");
message.Properties.Remove("Accept-Encoding");
message.Properties.Add("Accept-Header", "application/xml+");
var cf = new ChannelFactory<IRequestChannel>(binding, new EndpointAddress(new Uri("http://localhost:5050/PolicyService.svc")));
cf.Open();
var channel = cf.CreateChannel();
channel.Open();
var result = channel.Request(message);
channel.Close();
cf.Close();
return result;
}
What you receive back will be a Message, which you will need to deserialize, and there are a few OOTB ways of doing this, (Message.GetReaderAtBodyContents, Message.GetBody) in keeping w/the hand-rolled theme:
/// <summary>
/// Class MessageTransform.
/// </summary>
public static class MessageTransform
{
/// <summary>
/// Gets the envelope.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>XDocument.</returns>
public static XDocument GetEnvelope(Message message)
{
using (var memoryStream = new MemoryStream())
{
var messageBuffer = message.CreateBufferedCopy(int.MaxValue);
var xPathNavigator = messageBuffer.CreateNavigator();
var xmlWriter = XmlWriter.Create(memoryStream);
xPathNavigator.WriteSubtree(xmlWriter);
xmlWriter.Flush();
xmlWriter.Close();
memoryStream.Position = 0;
var xdoc = XDocument.Load(XmlReader.Create(memoryStream));
return xdoc;
}
}
/// <summary>
/// Gets the header.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>XNode.</returns>
public static XNode GetHeader(Message message)
{
var xdoc = GetEnvelope(message);
var strElms = xdoc.DescendantNodes();
var header = strElms.ElementAt(1);
return header;
}
/// <summary>
/// Gets the body.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="localName">Name of the local.</param>
/// <param name="namespaceName">Name of the namespace.</param>
/// <returns>IEnumerable<XElement>.</returns>
public static IEnumerable<XElement> GetBody(Message message, string localName, string namespaceName)
{
var xdoc = GetEnvelope(message);
var elements = xdoc.Descendants(XName.Get(localName, namespaceName));
return elements;
}
}
OR you could build your soap envelope by hand and use WebClient:
using System.Net;
using System.Xml.Linq;
public static class ClientHelper
{
public static string Post(string targetUrl, string action, string method, string key, string value)
{
var request = BuildEnvelope(method, key, value);
using (var webClient = new WebClient())
{
webClient.Headers.Add("Accept-Header", "application/xml+");
webClient.Headers.Add("Content-Type", "text/xml; charset=utf-8");
webClient.Headers.Add("SOAPAction", action);
var result = webClient.UploadString(targetUrl, "POST", request);
return result;
}
}
public static string BuildEnvelope(string method, string key, string value)
{
XNamespace s = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace d = "d4p1";
XNamespace tempUri = "http://tempuri.org/";
XNamespace ns = "http://Foo.bar.car";
XNamespace requestUri = "http://schemas.datacontract.org/2004/07/Foo.bar.car.Model.Policy";
var xDoc = new XDocument(
new XElement(
s + "Envelope",
new XAttribute(XNamespace.Xmlns + "s", s),
new XElement(
s + "Body",
new XElement(
ns + method,
new XElement(requestUri + "request",
new XElement(tempUri + key, value))
)
)
)
);
// hack - finish XDoc construction later
return xDoc.ToString().Replace("request xmlns=", "request xmlns:d4p1=").Replace(key, "d4p1:" + key);
}
which is called with:
return ClientHelper.Post("http://localhost:5050/PolicyService.svc", "http://Foo.bar.car/IPolicyService/GetPolicyData", "GetPolicyData", "REQ_POL_NBR", id);
Testing it in Fiddler would look something like this:
Post action: http://localhost:5050/PolicyService.svc
Header:
User-Agent: Fiddler
SOAPAction: http://Foo.bar.car/IPolicyService/GetPolicyData
Content-type: text/xml
Host: localhost:5050
Content-Length: 381
Body:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetPolicyData xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://Foo.bar.car">
<request xmlns:d4p1="http://schemas.datacontract.org/2004/07/Foo.bar.car.Model.Policy">
<d4p1:REQ_POL_NBR>1</d4p1:REQ_POL_NBR>
</request>
</GetPolicyData>
</s:Body>
</s:Envelope>
Again, this answer isn't trying to resolve how to invoke svcUtil differently, but to avoid calling it altogether, so I hope the edit gods don't ding me for that ;-)
My code above has been inspired by better developers than I, but I hope it helps.
http://blogs.msdn.com/b/stcheng/archive/2009/02/21/wcf-how-to-inspect-and-modify-wcf-message-via-custom-messageinspector.aspx
I would suggest you to generated wsdl proxy using command line utility and add generated proxy file in your project. It will work from every project and you can find the required configurations from output.config that will generate from command line utility.
If you require the wsdl command and options then I can provide you.
I'm not getting any return response from the web service, input message XML is being received Ok.
Trying to get and return a custom XML conforming to an integration standard, that is why I'm using S.S.C.Message as a parameter.
using System.ServiceModel.Channels;
[ServiceContract(Namespace = "urn:hl7-org:v3")]
public interface IHL7v3
{
[OperationContract(Name = "PRPA_IN201301UV02", Action = "urn:hl7-org:v3:PRPA_IN201301UV02")]
Message PIXManager_PRPA_IN201301UV02(Message input);
}
public class PIXService : IHL7v3
{
public Message PIXManager_PRPA_IN201301UV02(Message input)
{
// this code is being reached and executing fine
return Message.CreateMessage(MessageVersion.Soap12, "Op", "Content"); // will be replaced by an actual XML text
}
}
Service setup code:
Uri baseAddress = new Uri("http://192.168.2.120:31002/HL7Service");
ServiceHost selfHost = new ServiceHost(typeof(PIXService), baseAddress);
selfHost.Description.Name = "PIXManager";
selfHost.Description.Namespace = "urn:hl7-org:v3";
try
{
System.ServiceModel.Channels.Binding binder = new WSHttpBinding(SecurityMode.None);
binder.Name = "PIXManager_Binding_Soap12";
selfHost.AddServiceEndpoint(
typeof(IHL7v3),
binder,
"PIX");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
Console.WriteLine(smb.HttpGetUrl);
selfHost.Description.Behaviors.Add(smb);
selfHost.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex"
);
selfHost.Open();
ideas why?
Edit:
Added ReplyAction, still no reply
[OperationContract(Name = "PRPA_IN201301UV02", Action = "urn:hl7-org:v3:PRPA_IN201301UV02", ReplyAction = "urn:hl7-org:v3:MCCI_IN000002UV01")]
// ..
return Message.CreateMessage(MessageVersion.Soap12, "urn:hl7-org:v3:MCCI_IN000002UV01", "Something");
Change MessageVersion to MessageVersion.Soap12WSAddressing10
return Message.CreateMessage(MessageVersion.Soap12WSAddressing10, "Op", "Content");
The ReplyAction of your operation is set to one value (I can't remember exactly which, but it's the default value), and you're creating the response message with an Action property of Op. Try setting the ReplyAction property in the OperationContract, and use the same value when creating the response message.
I am trying to create a WCF service at runtime. My service interface is:
[ServiceContract]
public interface IInformationService : IService
{
[OperationContract]
[WebInvoke(Method = "Get", ResponseFormat = WebMessageFormat.Json,
UriTemplate = "Test", RequestFormat = WebMessageFormat.Json)]
string Test();
}
I am serving my service as follows:
var httpEnumerator = ImplementedContracts.Values.GetEnumerator();
httpEnumerator.MoveNext();
var httpContractType = httpEnumerator.Current.ContractType;
var webBinding = new WebHttpBinding()
{
Security =
{
Mode = WebHttpSecurityMode.None
}
};
var httpEndpoint = AddServiceEndpoint(
httpContractType,
webBinding, baseAddress+/Get"
);
httpEndpoint.Behaviors.Add(new CustomEndpointBehavior());
The ServiceHost is created by this method:
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var host = new WcfServiceHost(serviceType, baseAddresses);
if (host.Description.Behaviors.Contains(typeof(ServiceDebugBehavior)))
{
(host.Description.Behaviors[typeof(ServiceDebugBehavior)] as
ServiceDebugBehavior).IncludeExceptionDetailInFaults = true;
}
else
{
var debug = new ServiceDebugBehavior
{
IncludeExceptionDetailInFaults = true
};
host.Description.Behaviors.Add(debug);
}
if (host.Description.Behaviors.Contains(typeof(ServiceMetadataBehavior)))
{
(host.Description.Behaviors[typeof(ServiceMetadataBehavior)] as ServiceMetadataBehavior).HttpGetEnabled = true;
(host.Description.Behaviors[typeof(ServiceMetadataBehavior)] as ServiceMetadataBehavior).HttpsGetEnabled = true;
}
else
{
var smb = new ServiceMetadataBehavior
{
HttpGetEnabled = true,
HttpsGetEnabled = true
};
host.Description.Behaviors.Add(smb);
}
host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpsBinding(),
"mex"
);
host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex"
);
return host;
}
Service route creation:
var serviceRoute = new ServiceRoute(
"wcf.service/" + service.Value.Name,
new WcfServiceHostFactory(),
service.Value
);
if (!RouteTable.Routes.Contains(serviceRoute))
{
RouteTable.Routes.Add(serviceRoute);
}
When I try to access my service from a web browser using the address
http://localhost/Werp.View/wcf.service/InformationService/Get/Test
I obtain the following error:
<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
<Code>
<Value>Sender</Value>
<Subcode>
<Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">
a:ActionNotSupported
</Value>
</Subcode>
</Code>
<Reason>
<Text xml:lang="en-US">
The message with Action '' cannot be processed at the receiver, due to a
ContractFilter mismatch at the EndpointDispatcher. This may be because of
either a contract mismatch (mismatched Actions between sender and receiver)
or a binding/security mismatch between the sender and the receiver. Check
that sender and receiver have the same contract and the same binding
(including security requirements, e.g. Message, Transport, None).
</Text>
</Reason>
Can anyone help me?
If you don't need specific WCF features or you have mandate to use WCF you should consider using different stack for REST based services. For example ASP.NET web API or ServiceStack. It looks like a lot of work to do a simple REST call.
If you turn on service diagnostics this might help diagnosing the problem. You can see this SO for detailed instructions
You can also refer to this SO: WCF - ContractFilter mismatch at the EndpointDispatcher exception for some ideas.
My problem has been solved when I added WebHttpBehavior to endpoint
httpEndpoint.Behaviors.Add(new WebHttpBehavior());
In my case, I needed to add a HTTP header to the request called SOAPAction, where the value was set to the xmlns path to the service I was requesting.
This is the scenario: I have a WCF service running, who communicates with this method, in C#:
public bool ValidateUser(UserPass up)
{
initializeAttributes();
IMembershipService Member = new AccountMembershipService();
bool login = Member.ValidateUser(up.User, up.Pass);
return login;
}
The parameter are encapsulated in this class:
[DataContract]
public class UserPass
{
string user = "";
string pass = "";
string email = "";
[DataMember]
public string User
{
get { return user; }
set { user = value; }
}
[DataMember]
public string Pass
{
get { return pass; }
set { pass = value; }
}
[DataMember]
public string Email
{
get { return email; }
set { email = value; }
}
}
Now, I want to connect to the server via an Android application, now, my question is, how can I replicate the UserPass class in Java, so the ValidateUser method can receive its parameter in a way it can understands it.
for reference, this is the code where I'm obtaining the User and Password:
private void validateUser(String user, String pass)
{
String SOAP_ACTION = "http://tempuri.org/IUserService/ValidateUser/";
String METHOD_NAME = "ValidateUser";
String NAMESPACE = "http://tempuri.org/";
String URL = "http://10.0.2.2/UserService.svc";
AlertDialog popup;
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty(user, pass);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut = request;
envelope.dotNet = true;
HttpTransportSE httpTransport = new HttpTransportSE(URL);
try
{
httpTransport.call(SOAP_ACTION, envelope); //here's the exception!!
Object response = envelope.getResponse();
popup = createAlertDialog("Respuesta",response.toString(),"OK");
popup.show();
}
catch (Exception exception)
{
String exceptionStr=exception.toString();
popup = createAlertDialog("Exception!!",exceptionStr,"OK");
popup.show();
}
}
The exception it throws is xmlpullparserexception, which, according to my understanding, is because of a missmatch between the parameters of the request and the actual method.
Many thanks for reading my question, and many more for those who can answer it :)
EDIT:
I finnaly got how to compare the XMLs... now, this is what my SOAP is providing:
<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d="http://www.w3.org/2001/XMLSchema"
xmlns:c="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header />
<v:Body>
<ValidateUser xmlns="http://tempuri.org/" id="o0" c:root="1">
<User i:type="d:string">someuser</User>
<Pass i:type="d:string">somepass</Pass>
<Email i:type="d:string"></Email>
</ValidateUser>
</v:Body>
and this is what it SHOULD have made (retrieved from WCF Test Client application from Visual Studio 2010):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IUserService/ValidateUser</Action>
</s:Header>
<s:Body>
<ValidateUser xmlns="http://tempuri.org/">
<up xmlns:d4p1="http://schemas.datacontract.org/2004/07/LiveAndesWCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:Email i:nil="true" />
<d4p1:Pass>somepass</d4p1:Pass>
<d4p1:User>someuser</d4p1:User>
</up>
</ValidateUser>
</s:Body>
</s:Envelope>
Now, I'm lost on how to code my soap code to have it generate a xml file like the latter one.
Many thanks again.
have you tried to look at the xml created by the soap call? you can compare it to the xml created by a .net proxy. maybe this helps to find a solution.
here is how you can enable the logging of the soap calls:
http://msdn.microsoft.com/en-us/library/ms730064.aspx
This line looks suspect to me:
request.addProperty(user, pass);
As far as I can tell, SoapObject comes from the KSOAP2 library, and according to the docs, addProperty takes the name of the property and the value. To set user and pass, I would expect something more like this:
request.addProperty("user", user);
request.addProperty("pass", pass);
Currently, it looks like you're adding a single property named using the value of the user parameter. If the endpoint is expecting at least 2 arguments, then this could be the source of your mismatch.
Also, is the value "Email", from the UserPass wrapper class, optional? As I don't see it being set anywhere, and the wrapper class suggests it's required by the SOAP request