'WebException' error on back button even when calling 'void' async method - wcf

I have a windows phone app that allows the user to interact with it. Each interaction will always result in an async WCF call.
In addition to that, some interactions will result in opening the browser, maps, email, etc...
The problem is that, when hitting the back button, I sometime get the following error
"An error (WebException) occurred while transmitting data over the HTTP channel."
with the following stack trace:
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.OnGetResponse(IAsyncResult result)
at System.Net.Browser.ClientHttpWebRequest.<>c__DisplayClassa.<InvokeGetResponseCallback>b__8(Object state2)
at System.Threading.ThreadPool.WorkItem.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadPool.WorkItem.doWork(Object o)
at System.Threading.Timer.ring()
My understanding is that it's happening because my app opened another app (browser, maps, etc) before it had the time to execute the EndMyAsyncMethod(System.IAsyncResult result). Fair enough...
What's really annoying is that it seems it should get fixed by cloning the server-side method, only making it void with the following operation contract [OperationContract(IsOneWay = true)] but I'm still getting the error.
What's worse is that the exception is thrown in a system-generated part of the code and, thus, cannot be manually caught causing the app to just crash.
I simply don't understand the need to execute an Endxxx method when it's explicitely marked as OneWay and void.
EDIT
I did find a similar issue here. It does seem that it is related to the message getting to the service (not the client callback). My next question is:
if I'm now calling a method marked AsyncPattern and OneWay, what exactly should I be waiting for on the client to be sure the message was transmitted successfully?
This is new service definition:
[OperationContract(IsOneWay = true, AsyncPattern = true)]
IAsyncResult BeginCacheQueryWithoutCallback(string param1, QueryInfoDataContract queryInfo, AsyncCallback cb, Object s);
void EndCacheQueryWithoutCallback(IAsyncResult r);
And the implementation:
public IAsyncResult BeginCacheQueryWithoutCallback(string param1, QueryInfoDataContract queryInfo, AsyncCallback cb, Object s)
{
// do some stuff
return new CompletedAsyncResult<string>("");
}
public void EndCacheQueryWithoutCallback(IAsyncResult r)
{
}

The only thing that will guarantee that message has been delivered for One-Way binding is turning on reliable messaging and ensuring that there are no communication errors (wrong address, binding, etc.) This is the list of bindings that support reliable messaging:
basicHttpBinding - RM not supported
wsHttpBinding - RM supported, not default
wsDualHttpBinding - RM implicit
netTcpBinding - RM supported, not default
For example for tcpBinding:
<binding>
<netTcpBinding>
<binding name="MyTcpBinding">
<reliableSession enabled="true" />
</binding>
</netTcpBinding>
</binding>
Or:
<customHttpBinding>
<binding configurationName="customReliableBinding">
<reliableSession ordered="true" />
</binding>
</customBinding>

Related

WCF - IErrorHandler vs Authentication

I'm writing a WCF service with some authentication and a custom error handler. However, I'm coming up against this problem: my implementation of IErrorHandler is not getting hit when the authentication throws an exception, but runs just fine with other exeptions.
Does authentication run before IErrorHandler gets built? Am I barking up the wrong tree trying to get it to catch those errors?
Yes, I have tried (and am) throwing a FaultException in my authentication, not SecurityTokenException.
So first thing is to make sure that your custom Error Handler is also implementing IServiceBehavior. IServiceBehavior requires that you implement a couple other methods but the important one is "ApplyDispatchBehavior", in which you must add the ErrorHandler to the channel dispatchers.
C#
public class CustomErrorHandler: IServiceBehavior, IErrorHandler
{
public bool HandleError(Exception error)
{
//Return True here if you want the service to continue on as if
// the error was handled
return true;
}
public void ProvideFault(Exception error,
MessageVersion version,
ref Message fault)
{
FaultException fe = new FaultException(
new FaultReason(error.Message),
new FaultCode("Service Error"));
MessageFault mf = fe.CreateMessageFault();
fault = Message.CreateMessage(version, mf, fe.Action);
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
IErrorHandler eh = new CustomErrorHandler();
foreach (ChannelDsipatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = cdb as ChannelDispatcher;
cd.ErrorHandlers.Add(eh);
}
}
public void AddBindingParameters(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
//Add binding parameters if you want, I am not
}
public void Validate(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
//Add custom fault validation here if you want
}
}
Then you need to add the CustomErrorHandler as a service behavior and add the behavior
web.config
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="ErrorHandler"
type="ServiceNamespace.CustomErrorHandler, ServiceNamespace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior1">
<!--Put other behaviors for your service here then add the next line-->
<ErrorHandler />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
This way all your thrown exceptions will be converted to faults to return back to the client.
In the case of SecurityTokenExceptions, you do not want to convert those to Fault Exceptions right away. You actually do want to throw these as SecurityTokenExceptions in the custom validation in order for the service/server to recognize that the security authorization failed, and automatically returns as a fault equiv of a "403 : Access Denied". I am not 100% but I think that the custom auth and validation pieces happen before custom service behaviors, like the error handler, are loaded. Unfortunately, if you need to troubleshoot something in your auth, you will need to turn on WCF tracing on the service, see this article titled "How to turn on WCF Tracing".
If you need to log failed auth attempts, you will probably need to put it directly in your custom validator.

MsmqException (0xC00E0051) after 60 seconds

I am using the netMsmqBinding with a transactional queue, and although the WCF service is called without problems, the service is throwing a MsmqException just 60 seconds after the message is processed.
This is the exception:
System.ServiceModel.MsmqException (0xC00E0051): An error occurred while receiving a message from the queue: Unrecognized error
-1072824239 (0xc00e0051). Ensure that MSMQ is installed and running. Make sure the queue is available to receive from. at
System.ServiceModel.Channels.MsmqInputChannelBase.TryReceive(TimeSpan
timeout, Message& message) at
System.ServiceModel.Dispatcher.InputChannelBinder.TryReceive(TimeSpan
timeout, RequestContext& requestContext) at
System.ServiceModel.Dispatcher.ErrorHandlingReceiver.TryReceive(TimeSpan
timeout, RequestContext& requestContext)
I have done some research, debugging and tracing and I have found that when a new message is received, two transactions are opened, the first one is committed just after the service execution, but the second one is never committed, so then, after 60 seconds, the DTC aborts it throwing the MsmqException.
This is the operation definition:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SomeOperation(SomeParameter parameter)
{
// business logic
}
Any ideas about what is happening, and how can I solve this issue?
UPDATE:
Config:
<netMsmqBinding>
<binding name="TransactionalMsmqBinding" exactlyOnce="true" deadLetterQueue="System" receiveErrorHandling="Move">
<security mode="None"/>
</binding>
</netMsmqBinding>
...
<service name="SomeNamespace.SomeService">
<endpoint contract="SomeNamespace.ISomeService" bindingConfiguration="TransactionalMsmqBinding" binding="netMsmqBinding" address="net.msmq://localhost/private/services/someservice.svc">
</endpoint>
<endpoint contract="SomeNamespace.IAnotherService" bindingConfiguration="TransactionalMsmqBinding" binding="netMsmqBinding" address="net.msmq://localhost/private/services/anotherservice.svc">
</endpoint>
</service>
Service Implementation:
[ExceptionShieldingBehavior(typeof(ArgumentValidationException), typeof(ValidationServiceException))]
[AuthorizationAndAuditBehaviour]
[ServiceBehavior(Namespace = GlobalConstants.ServiceContractNamespace)]
public class SomeService: ISomeService, IAnotherService
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SomeOperation(SomeParameter parameter)
{
// business logic
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void AnotherOperation(AnotherParameter parameter)
{
// business logic
}
}
Service Contracts:
[ServiceContract(Namespace = GlobalConstants.ServiceContractNamespace)]
public interface ISomeService
{
[OperationContract(IsOneWay = true)]
void SomeOperation(SomeParameter parameter);
}
[ServiceContract(Namespace = GlobalConstants.ServiceContractNamespace)]
public interface IAnotherService
{
[OperationContract(IsOneWay = true)]
void AnotherOperation(AnotherParameter parameter);
}
Complete behavior:
The client sends a message
The service is activated
The DTC starts two transactions (I can see them in the DTC monitor and in the TransactionManager.DistributedTransactionStarted event)
The first transaction finishes as soon as the operation finishes
The second transaction is aborted 60 seconds after (MsmqException is thrown)
The wcf host (IIS) is sometimes faulted (I have some code to automatically recover it, apparently this behaviour has changed in .net 4)
If the host was broken and automatically recovered, all will happen again on next message
If the host was not broken, the second transaction won't start the next time and everything will work without problems :).
If I recycle the AppPool, the problem starts again
I have found the problem.
As I am exposing the same Service using two different msmq Endpoints, for some weird reason the SMSvcHost.exe process activates the same Endpoint twice.
I have just written a post with the solution: http://blog.jorgef.net/2011/07/msmqexception.html
I hope it helps.
Jorge

404 Error when TFS 2010 Sends SOAP Alert to a WCF 4.0 Service

I'm trying to write a WCF 4.0 service that will receive SOAP alerts from TFS 2010. Here is my service contract:
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
public interface IService1
{
[OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml);
}
I am using this binding configuration for my service endpoint:
<bindings>
<wsHttpBinding>
<binding name="noSecurity">
<security mode="None"/>
</binding>
</wsHttpBinding >
</bindings>
Having registered a TFS alert using BISSUBSCRIBE.EXE and pointed it to my service, every time it is triggered my service is not invoked and instead I see the following in the TfsJobAgent log:
Notification not delivered.
Notification: WorkItemChangedEvent (DeliveryType: Soap; Address: http://192.168.10.10/TrafficLight/Service1.svc)
Exception: Microsoft.TeamFoundation.TeamFoundationServiceUnavailableException: Team Foundation services are not available from server http://192.168.10.10/TrafficLight/Service1.svc. Technical information (for administrator):
HTTP code 404: Not Found ---> System.Net.WebException: The remote server returned an error: (404) Not Found.
at System.Net.HttpWebRequest.GetResponse()
at Microsoft.TeamFoundation.Client.TeamFoundationClientProxyBase.AsyncWebRequest.ExecRequest(Object obj)
--- End of inner exception stack trace ---
at Microsoft.TeamFoundation.Client.TeamFoundationClientProxyBase.ProcessHttpResponse(HttpWebResponse response, Stream responseStream, WebException webException, XmlReader& xmlResponseReader)
at Microsoft.TeamFoundation.Client.TeamFoundationClientProxyBase.ExecWebServiceRequest(HttpWebRequest request, XmlWriter requestXml, String methodName, HttpWebResponse& response)
at Microsoft.TeamFoundation.JobService.Extensions.Core.TeamFoundationNotificationClient.Notify(String eventXml, String tfsIdentityXml, Subscription subscription)
at Microsoft.TeamFoundation.JobService.Extensions.Core.NotificationJobExtension.SendSoapNotification(TeamFoundationRequestContext requestContext, TeamFoundationNotification notification, TeamFoundationIdentityService identityService)
(This is taken from the [Tfs_Configuration].[dbo].[tbl_JobHistory] table of my TFS 2010 installation)
Oddly enough, when I try my service's URL in internet explorer on the same machine where the TfsJobAgent is running, I receive the standard "You have created a service." web page auto-generated by WCF and not a 404 error.
At last, my question: Why is the TFS Job Agent receiving a 404 error from my service which seems to be properly configured? How can I resolve this issue?
Update: I've tried rewriting my service as an ASMX web service and it's working well. Below is the implementation. I still want to learn how to achieve the same using WCF 4.0 so any help would be greatly appreciated.
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class WebService1 : System.Web.Services.WebService
{
[SoapDocumentMethod("http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", RequestNamespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
[WebMethod]
public void Notify(string eventXml, string tfsIdentityXml)
{
// log incoming event...
}
I have created this succesfully - http://www.ewaldhofman.nl/post/2010/08/02/How-to-use-WCF-to-subscribe-to-the-TFS-2010-Event-Service-rolling-up-hours.aspx - and it seems that you are using the same steps.
Did you also specify the wsHttpBinding for the endpoint?

Error calling a WCF REST service using JSON. length quota (8192) exceeded

I’m having a WCF REST service hosted in IIS using .NET 4 RC. The POST calls to the service are serialized using JSON. Everything works fine until the size of one of the DataMember (string) is longer than 8K. In this case I receive the error described below indicating the MaxStringContentLength has been exceeded. The maxStringContentLength attribute for the endPoint has been increased and it is correctly read from the config file.
Web config is:
<services>
<service name="MyServiceServer" >
<endpoint address="http://localhost/MyService" kind="webHttpEndpoint" endpointConfiguration="serviceEndPoint" contract="IMyService">
</endpoint>
</service>
</services>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="serviceEndPoint" maxReceivedMessageSize="2048000" maxBufferSize="2048000" maxBufferPoolSize="0">
<readerQuotas maxStringContentLength="2048000" maxArrayLength="2048000" maxDepth ="65000"/>
<security mode="None">
<transport clientCredentialType="None"/>
</security>
</standardEndpoint>
</webHttpEndpoint>
</standardEndpoints>
IMyService interface is defined as:
public interface IMyService
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/request", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
void MyMehod(<Class Type> obj);
}
Complete Error Message is:
“The server encountered an error processing the request. The exception message is 'There was an error deserializing the object of type . The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.'. See server logs for more details. The exception stack trace is: at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver) at System.Runtime.Serialization.Json.DataContractJsonSerializer.ReadObject(XmlDictionaryReader reader, Boolean verifyObjectName) at System.ServiceModel.Dispatcher.SingleBodyParameterMessageFormatter.DeserializeRequest(Message message, Object[] parameters) at System.ServiceModel.Dispatcher.DemultiplexingDispatchMessageFormatter.DeserializeRequest(Message message, Object[] parameters) at System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(Message message, Object[] parameters) at System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc& rpc) at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)”
This works, just make sure to have a full absolute URL as your endpoint address. If you get crafty and try to use a relative path, or if you omit .svc it will bomb with the strange reader quota error once the request gets too large --
I would file this under a Bug for WCF because either:
relative URLs should be disallowed (and an appropriate exception thrown)
or
the reader quota should work with relative paths as well
Insert into your web.config:
<configuration>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingConfig">
<readerQuotas maxStringContentLength="2048000" />
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
and insert attribute bindingConfiguration="webHttpBindingConfig" into your endpoint
I had similar problems but with .NET 3.5
I had no problems on the server log, so the problem was on the client.
Seems that the configuration with the max values increased was not read and used...
So I solved passing the name of the endpoint EXPLICITLY in the constructor of the WebChannelFactory, using another overload.
WAS:
WebChannelFactory<IWKRestTest> factory = new WebChannelFactory<IWKRestTest>(new Uri(XXX));
factory.Credentials.UserName.UserName = K_USERNAME;
factory.Credentials.UserName.Password = K_PASSWORD;
IWKRestTest proxy = factory.CreateChannel();
IS:
WebChannelFactory<IWKRestTest> factory = new WebChannelFactory<IWKRestTest>("IWKRestTestService");
and in the app.config there's:
The Uri is indicated in the endpoint node but there you find also the bindingConfiguration and so on, so all the new increased limits now works.

BizTalk SendPort WCF Calling .asmx web service using WS-Security

Everything I've found so far says I should be able to use WCF to call a .asmx web service that uses WS-Security. The question is how to configure the WCF-Port. I'm using WCF-BasicHttp. First of all, is that okay? Second, how to enter the user/pass properly. On the security tab, which "Security Mode" should I pick?
The only one that seems to let me enter credentials is TransportWithMessageCredential, then I can click the "Edit" button by username credentials and enter a user/pass.
But when I did, I got this:
<soap:Fault xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode xmlns:q0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">q0:Security</faultcode>
<faultstring>Microsoft.Web.Services3.Security.SecurityFault: Security requirements are not satisfied because the security header is not present in the incoming message.
at Microsoft.Web.Services3.Design.UsernameOverTransportAssertion.ServiceInputFilter.ValidateMessageSecurity(SoapEnvelope envelope, Security security)
at MSB.RCTExpress.Presentation.Web.UsernameOverTransportAssertion.ServiceInputFilter.ValidateMessageSecurity(SoapEnvelope envelope, Security security)
in C:\projects\la1safe1\RCT Express\MSB.RCTExpress\3.10\Presentation.Web\UsernameOverTransportNoSendNone.cs:line 27
at Microsoft.Web.Services3.Security.ReceiveSecurityFilter.ProcessMessage(SoapEnvelope envelope)
at Microsoft.Web.Services3.Pipeline.ProcessInputMessage(SoapEnvelope envelope)
at Microsoft.Web.Services3.WseProtocol.FilterRequest(SoapEnvelope requestEnvelope)
at Microsoft.Web.Services3.WseProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)</faultstring>
<faultactor>http://rct3.msbexpress.net/demo/ExpressLync/ValuationService.asmx</faultactor>
</soap:Fault>
Any ideas?
Thanks,
Neal Walters
Follow-up to TomasR's post - using WS-HTTP binding:
1) BizTalk "Consume WCF Wizard" builds a custom binding file and a WS-BasicHTTP Binding file, so I changed SendPort, and manually copied over all the configurations.
Set as follows:
Security Mode: Message
Message Client Credential Type: UseName
Algorithm Suite: Basic256 [I had no idea what to put here]
I also checked two other boxes:
a) Negotiate service credential [if I don't check this, it wants a "thumbprint"]
b) Establish security context [also tried not checking this one]
2) Ran and got this error:
Description:
The adapter failed to transmit message going to send port "WcfSendPort_ValuationServicePort_ValuationServicePortSoap" with URL "http://rct3.msbexpress.net/demo/ExpressLync/ValuationService.asmx". It will be retransmitted after the retry interval specified for this Send Port.
Details:"System.NullReferenceException: Object reference not set to an instance of an object.
Server stack trace:
at System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout)
at System.ServiceModel.Security.SspiNegotiationTokenProvider.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.TlsnegoTokenProvider.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Security.CommunicationObjectSecurityTokenProvider.Open(TimeSpan timeout)
at System.ServiceModel.Security.SecurityUtils.OpenTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout)
at System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(TimeSpan timeout)
at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.DoOperation(SecuritySessionOperation operation,
EndpointAddress target, Uri via, SecurityToken currentToken, TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.GetTokenCore(TimeSpan timeout)
at System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionClientSettings`1.ClientSecuritySessionChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open()
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at System.ServiceModel.ICommunicationObject.Open()
at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.GetChannel[TChannel](IBaseMessage bizTalkMessage,
ChannelFactory`1& cachedFactory)
at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.SendMessage(IBaseMessage bizTalkMessage)".
Now tried custom binding, added user/pass and get this error:
<soap:Fault xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Code>
<soap:Value xmlns:q0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">q0:Security</soap:Value>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="en">Microsoft.Web.Services3.Security.SecurityFault:
Security requirements are not satisfied because the security header is not present in the incoming message.
at Microsoft.Web.Services3.Design.UsernameOverTransportAssertion.ServiceInputFilter.ValidateMessageSecurity(SoapEnvelope envelope,
Security security)
at MSB.RCTExpress.Presentation.Web.UsernameOverTransportAssertion.ServiceInputFilter.ValidateMessageSecurity
(SoapEnvelope envelope, Security security) in
C:\projects\la1safe1\RCT Express\MSB.RCTExpress\3.10\Presentation.Web\UsernameOverTransportNoSendNone.cs:line 27
at Microsoft.Web.Services3.Security.ReceiveSecurityFilter.ProcessMessage(SoapEnvelope envelope)
at Microsoft.Web.Services3.Pipeline.ProcessInputMessage(SoapEnvelope envelope)
at Microsoft.Web.Services3.WseProtocol.FilterRequest(SoapEnvelope requestEnvelope)
at Microsoft.Web.Services3.WseProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)</soap:Text>
</soap:Reason>
<soap:Node>http://rct3.msbexpress.net/demo/ExpressLync/ValuationService.asmx</soap:Node>
</soap:Fault>
My next attempt, went back to WS-HTTP, but tried to put the User/Pass in a message assignment rather than in the SendPort:
msgRCTGetRequest(SOAP.Username) = "myuser";
msgRCTGetRequest(SOAP.Password) = "mypass";
//msgRCTGetRequest(SOAP.UseSoap12) = true;
Resulted in this error:
<soap:Fault xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Code>
<soap:Value>soap:Sender</soap:Value>
</soap:Code><soap:Reason>
<soap:Text xml:lang="en">System.Web.Services.Protocols.SoapHeaderException: WSE012: The input was not a valid SOAP message because the following information is missing: action.
at Microsoft.Web.Services3.Utilities.AspNetHelper.SetDefaultAddressingProperties(SoapContext context, HttpContext httpContext)
at Microsoft.Web.Services3.WseProtocol.CreateRequestSoapContext(SoapEnvelope requestEnvelope)
at Microsoft.Web.Services3.WseProtocol.FilterRequest(SoapEnvelope requestEnvelope)
at Microsoft.Web.Services3.WseProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)</soap:Text>
</soap:Reason>
</soap:Fault>
Fifth attempt, about to give up and open a Microsoft ticket:
msgRCTGetRequest(WCF.UserName) = "myuser";
msgRCTGetRequest(WCF.Password) = "mypass";
msgRCTGetRequest(WCF.Action) = "GetPropertyInfoSourceRecordPolicyNum";
msgRCTGetRequest(SOAP.MethodName) = "GetPropertyInfoSourceRecordPolicyNum";
msgRCTGetRequest(SOAP.Username) = "myuser";
msgRCTGetRequest(SOAP.Password) = "mypass";
same error as fourth attempt.
According to the doc of the vendor providing the web service, I should put the user in W-Security UsernameToken element, the password in WS-Security password, and set the element's attribute to "PasswordDigest". It also says "This token should be added to the SOAP request for the Web method." I'm not sure how this translates from the old WSE3 days to the new WCF days.
Neal, for WS-Security, you need to use the WCF-WsHttp binding/Adapter. WCF-BasicHttp is only for the simpler scenarios where the WS-* protocols are not needed.
.NET 4.0 and .NET 3.5 SP1 with hotfix 971831 allow WS-Security over http transport. Try using this sample binding:
<customBinding>
<binding name="httpAndWSSecurity">
<security authenticationMode="UserNameOverTransport"
allowInsecureTransport="true"/>
<textMessageEncoding messageVersion="Soap11WSAddressingAugust2004" />
<httpTransport/>
</binding>
Also see this MSDN article on SecurityBindingElement.AllowInsecureTransport
Use custom binding, and from the BizTalk send port, click configure, then go to the right-most tab which says "Import/Export". Paste the following XML into a file (sample.config) and then import it into the configuration port. This basically saves the time of manually typing a lot of stuff on the binding tab.
<configuration>
<system.serviceModel>
<client>
<endpoint
address="http://rct3.msbexpress.net/demo/ExpressLync/ValuationService.asmx"
binding="customBinding"
bindingConfiguration="ValuationServicePortSoap12"
contract="BizTalk"
name="WcfSendPort_ValuationServicePort_ValuationServicePortSoap12"/>
</client>
<bindings>
<customBinding>
<binding name="ValuationServicePortSoap12">
<security authenticationMode="UserNameOverTransport"
messageProtectionOrder="SignBeforeEncrypt"
includeTimestamp="true"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireDerivedKeys="false"
requireSignatureConfirmation="false"/>
<textMessageEncoding messageVersion="Soap11WSAddressingAugust2004"/>
<httpsTransport />
</binding>
</customBinding>
</bindings>
</system.serviceModel>
</configuration>
The above is not very intuitive (I'm still waiting for a link from Microsoft which describes this is more detail).
Then you still specify the user/pass on the credentials tab.
However, this caused a problem for us, in that the vendor's .asmx web service we were calling did not have IIS set to "requires SSL". Apparently, that is a requirement for this to work with WCF. In other words, it works fine with WSE3 calling .NET to .NET, but when trying to call WCF to .asmx, WCF has a slightly more stringent requirement.
Neal Walters