I'm trying to log the requests and responses (the raw XML SOAP envelope) between a console application developed by me and a specific third party remote SOAP web service to database for audit purposes, and I can't find a way to do it.
Ideally what I'd like to do is getting the request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:SayHello>
<tem:name>Albireo</tem:name>
</tem:SayHello>
</soapenv:Body>
</soapenv:Envelope>
and the response
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<SayHelloResponse xmlns="http://tempuri.org/">
<SayHelloResult>Hello, Albireo.</SayHelloResult>
</SayHelloResponse>
</s:Body>
</s:Envelope>
and save them in the database.
So far every tutorial on the net I found boils down to two approaches, the SoapExtension method and the tracing method.
The SoapExtension method
The SoapExtension method is based on the SOAP Message Modification Using SOAP Extensions guide, in this method you create a class inheriting from SoapExtension and hook it in the application's configuration, the class' ProcessMessage method will allow you to intercept the SOAP messages.
This is an example of the class inherited from SoapExtension:
namespace Playground.Client
{
using System;
using System.Web.Services.Protocols;
public class SoapLogger : SoapExtension
{
public override object GetInitializer(System.Type serviceType)
{
throw new NotImplementedException();
}
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
throw new NotImplementedException();
}
public override void Initialize(object initializer)
{
throw new NotImplementedException();
}
public override void ProcessMessage(SoapMessage message)
{
throw new NotImplementedException();
}
}
}
And this is how it is wired in the configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0"
sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IGreeterService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8080/greeter"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IGreeterService"
contract="Services.IGreeterService"
name="BasicHttpBinding_IGreeterService" />
</client>
</system.serviceModel>
<system.web>
<webServices>
<soapExtensionTypes>
<add group="0"
priority="1"
type="Playground.Client.SoapLogger" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
The problem with this method is it seems to work only for web applications, trying to implement it in a console application yield no result.
The tracing method
The tracing method is based upon the Configuring Message Logging guide, in this method you enable .NET's tracing for every SOAP/WCF communication in the application and dump the log somewhere (more information on the configuration can be found in Recommended Settings for Tracing and Message Logging).
This is an example of the tracing configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0"
sku=".NETFramework,Version=v4.5" />
</startup>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
propagateActivity="true"
switchValue="Verbose, ActivityTracing">
<listeners>
<add initializeData="ServiceModel.svclog"
name="ServiceModel"
type="System.Diagnostics.XmlWriterTraceListener" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add initializeData="MessageLogging.svclog"
name="MessageLogging"
type="System.Diagnostics.XmlWriterTraceListener" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IGreeterService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8080/greeter"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IGreeterService"
contract="Services.IGreeterService"
name="BasicHttpBinding_IGreeterService" />
</client>
<diagnostics>
<endToEndTracing activityTracing="true"
messageFlowTracing="true"
propagateActivity="true" />
<messageLogging logEntireMessage="true"
logKnownPii="true"
logMalformedMessages="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true" />
</diagnostics>
</system.serviceModel>
</configuration>
The content of ServiceModel.svclog and MessageLogging.svclog can be found in a GitHub's Gist as it's too big to fit here.
The problem with this method is it logs every SOAP/WCF message in the application and it seems the generated logs are not really useful, they contains loads of informations and I can't understand if and how filter only what I'm interested in, the only practical way to read them seems to be Microsoft's Service Trace Viewer.
I've tried to add a custom TraceListener too:
namespace Playground.Client
{
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Linq;
public class CustomTraceListener : TraceListener
{
public override void Write(string message)
{
File.AppendAllLines("CustomTraceListener.txt", new[] { message });
}
public override void WriteLine(string message)
{
message = this.FormatXml(message);
File.AppendAllLines("CustomTraceListener.txt", new[] { message });
}
private string FormatXml(string message)
{
using (var stringWriter = new StringWriter())
{
var xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Encoding = Encoding.UTF8;
xmlWriterSettings.Indent = true;
xmlWriterSettings.OmitXmlDeclaration = true;
using (var xmlTextWriter = XmlWriter.Create(stringWriter, xmlWriterSettings))
{
XDocument.Parse(message).Save(xmlTextWriter);
}
return Convert.ToString(stringWriter);
}
}
}
}
But even though it allows me to intercept the messages, it doesn't save any metadata:
<MessageLogTraceRecord Time="2013-07-16T10:50:04.5396082+02:00" Source="ServiceLevelSendRequest" Type="System.ServiceModel.Channels.BodyWriterMessage" xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
<HttpRequest>
<Method>POST</Method>
<QueryString></QueryString>
<WebHeaders>
<VsDebuggerCausalityData>uIDPo4bOsuSXlSVEkmfof4AP2psAAAAAlEIoNto3KEWKgCnIGryjp9f3wbRlp+ROhY9Oy6bed/cACQAA</VsDebuggerCausalityData>
</WebHeaders>
</HttpRequest>
<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/IGreeterService/SayHello</Action>
<ActivityId CorrelationId="964a7c4f-3b18-4b5d-8085-e00ae03b58d1" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">80101cc1-dfb5-4c8e-8d19-ec848ab69100</ActivityId>
</s:Header>
<s:Body>
<SayHello xmlns="http://tempuri.org/">
<name>Albireo</name>
</SayHello>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
<MessageLogTraceRecord Time="2013-07-16T10:50:04.6176897+02:00" Source="TransportSend" Type="System.ServiceModel.Channels.BodyWriterMessage" xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
<Addressing>
<Action>http://tempuri.org/IGreeterService/SayHello</Action>
<To>http://localhost:8080/greeter</To>
</Addressing>
<HttpRequest>
<Method>POST</Method>
<QueryString></QueryString>
<WebHeaders>
<VsDebuggerCausalityData>uIDPo4bOsuSXlSVEkmfof4AP2psAAAAAlEIoNto3KEWKgCnIGryjp9f3wbRlp+ROhY9Oy6bed/cACQAA</VsDebuggerCausalityData>
</WebHeaders>
</HttpRequest>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<ActivityId CorrelationId="964a7c4f-3b18-4b5d-8085-e00ae03b58d1" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">80101cc1-dfb5-4c8e-8d19-ec848ab69100</ActivityId>
</s:Header>
<s:Body>
<SayHello xmlns="http://tempuri.org/">
<name>Albireo</name>
</SayHello>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
With this information it's impossible to rebuild the request/response flow as all the messages are mixed together.
Compare them to the *.svclog generated by the native XmlWriterTraceListener:
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>0</EventID>
<Type>3</Type>
<SubType Name="Information">0</SubType>
<Level>8</Level>
<TimeCreated SystemTime="2013-07-16T08:50:04.6176897Z" />
<Source Name="System.ServiceModel.MessageLogging" />
<Correlation ActivityID="{80101cc1-dfb5-4c8e-8d19-ec848ab69100}" />
<Execution ProcessName="Playground.Client" ProcessID="4348" ThreadID="1" />
<Channel />
<Computer>ESP-DEV-9</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<MessageLogTraceRecord Time="2013-07-16T10:50:04.6176897+02:00" Source="TransportSend" Type="System.ServiceModel.Channels.BodyWriterMessage" xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
<Addressing>
<Action>http://tempuri.org/IGreeterService/SayHello</Action>
<To>http://localhost:8080/greeter</To>
</Addressing>
<HttpRequest>
<Method>POST</Method>
<QueryString></QueryString>
<WebHeaders>
<VsDebuggerCausalityData>uIDPo4bOsuSXlSVEkmfof4AP2psAAAAAlEIoNto3KEWKgCnIGryjp9f3wbRlp+ROhY9Oy6bed/cACQAA</VsDebuggerCausalityData>
</WebHeaders>
</HttpRequest>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<ActivityId CorrelationId="964a7c4f-3b18-4b5d-8085-e00ae03b58d1" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">80101cc1-dfb5-4c8e-8d19-ec848ab69100</ActivityId>
</s:Header>
<s:Body>
<SayHello xmlns="http://tempuri.org/">
<name>Albireo</name>
</SayHello>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>0</EventID>
<Type>3</Type>
<SubType Name="Information">0</SubType>
<Level>8</Level>
<TimeCreated SystemTime="2013-07-16T08:50:04.6957712Z" />
<Source Name="System.ServiceModel.MessageLogging" />
<Correlation ActivityID="{80101cc1-dfb5-4c8e-8d19-ec848ab69100}" />
<Execution ProcessName="Playground.Client" ProcessID="4348" ThreadID="1" />
<Channel />
<Computer>ESP-DEV-9</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<MessageLogTraceRecord Time="2013-07-16T10:50:04.6801549+02:00" Source="TransportReceive" Type="System.ServiceModel.Channels.BufferedMessage" xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
<HttpResponse>
<StatusCode>OK</StatusCode>
<StatusDescription>OK</StatusDescription>
<WebHeaders>
<Content-Length>207</Content-Length>
<Content-Type>text/xml; charset=utf-8</Content-Type>
<Date>Tue, 16 Jul 2013 08:50:04 GMT</Date>
<Server>Microsoft-HTTPAPI/2.0</Server>
</WebHeaders>
</HttpResponse>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header></s:Header>
<s:Body>
<SayHelloResponse xmlns="http://tempuri.org/">
<SayHelloResult>Hello, Albireo.</SayHelloResult>
</SayHelloResponse>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>
Here the <Correlation ActivityID="{80101cc1-dfb5-4c8e-8d19-ec848ab69100}" /> tag establishes a relation between each request and response, allowing a developer to rebuild the whole session.
Is there a way to accomplish what I'm trying to do?
If the service is registered as a WCF web-service (not as an old-school ASMX web-service) it's possible to do it through IClientMessageInspector and IEndpointBehavior.
First you have to create a class inheriting from IClientMessageInspector that will handle the logging of both the requests and the replies.
namespace Playground.Sandbox
{
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
public class MyClientMessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(
ref Message request,
IClientChannel channel)
{
// TODO: log the request.
// If you return something here, it will be available in the
// correlationState parameter when AfterReceiveReply is called.
return null;
}
public void AfterReceiveReply(
ref Message reply,
object correlationState)
{
// TODO: log the reply.
// If you returned something in BeforeSendRequest
// it will be available in the correlationState parameter.
}
}
}
Then you have to create a class inheriting from IEndpointBehavior that will register the inspector in the client.
namespace Playground.Sandbox
{
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
public class MyEndpointBehavior : IEndpointBehavior
{
public void Validate(
ServiceEndpoint endpoint)
{
}
public void AddBindingParameters(
ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(
ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher)
{
}
public void ApplyClientBehavior(
ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
{
var myClientMessageInspector = new MyClientMessageInspector();
clientRuntime.ClientMessageInspectors.Add(myClientMessageInspector);
}
}
}
Then when you want to use the behavior you can manually register it before using the service.
namespace Playground.Sandbox
{
public static class Program
{
public static void Main()
{
using (var client = new MyWcfClient())
{
var myEndpointBehavior = new MyEndpointBehavior();
client.Endpoint.Behaviors.Add(myEndpointBehavior);
// TODO: your things with the client.
}
}
}
}
If you don't want to register the behavior manually or you need it to be always active, you can register it in the configuration file.
First you need to create a class inheriting from BehaviorExtensionElement, this class will tell the .NET Framework which behavior will be applied and will create the instance when needed.
namespace Playground.Sandbox
{
using System;
using System.ServiceModel.Configuration;
public class MyBehaviorExtensionElement : BehaviorExtensionElement
{
protected override object CreateBehavior()
{
var myEndpointBehavior = new MyEndpointBehavior();
return myEndpointBehavior;
}
public override Type BehaviorType
{
get
{
return typeof(MyEndpointBehavior);
}
}
}
}
Then you need to register the BehaviorExtensionElement in the configuration file (only the relevant part of the configuration file are shown).
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime sku=".NETFramework,Version=v4.5"
version="v4.0" />
</startup>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="withMyBehaviorExtensionElement">
<myBehaviorExtensionElement />
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="..."
behaviorConfiguration="withMyBehaviorExtensionElement"
binding="..."
bindingConfiguration="..."
contract="..."
name="..." />
</client>
<extensions>
<behaviorExtensions>
<add name="myBehaviorExtensionElement"
type="Playground.Sandbox.MyBehaviorExtensionElement, Playground.Sandbox" />
</behaviorExtensions>
</extensions>
</system.serviceModel>
</configuration>
Now you can use the service without manually registering the behavior each time:
namespace Playground.Sandbox
{
public static class Program
{
public static void Main()
{
using (var client = new MyWcfService())
{
// TODO: your things with the client.
}
}
}
}
You can find a guide on how to do this in the MSDN's Message Inspectors article.
Related
Hi I am trying to consume a WSDL soap service in c# console application , the service is passed an account number and returns the details of that account.
I have tested the service using SOAP UI, all is good and working however now when I create a service class using svcutil to generate the class, I instantiate the client and try calling the method but it fails with the following error message. Please assist me. Please see error message and code below.
inner exception : There is an error in the XML document(43,9)
message : Input string was not in a correct format.
Code below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel;
namespace CRMTestApp
{
class Program
{
static void Main(string[] args)
{
var myBinding = new BasicHttpBinding();
var myednPoint = new EndpointAddress("SERVICE URL");
var myChannelFactory = new ChannelFactory<customerDetail_PortType>(myBinding, myednPoint);
customerDetail_PortType client = null;
try
{
getCustomerDetailsRequest request = new getCustomerDetailsRequest();
request.customerDetailIn = new customerDetailIn();
request.customerDetailIn.emmAccountNo = "3902269211";
//request.customerDetailIn.IDNumber = String.Empty;
//request.customerDetailIn.standNo = String.Empty;
client = myChannelFactory.CreateChannel();
client.getCustomerDetails(request);
//client.getCustomerDetails()
((ICommunicationObject)client).Close();
}
catch (Exception ex)
{
if (client != null)
{
((ICommunicationObject)client).Abort();
}
}
}
}
}
Here is my app.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="EMMCRMIntegration_webServices_providers_customerDetail_Binder" />
<readerQuotas maxDepth="999999" maxStringContentLength="999999" maxArrayLength="999999" maxBytesPerRead="999999" maxNameTableCharCount="999999" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="SERVICE URL"
binding="basicHttpBinding"
bindingConfiguration="EMMCRMIntegration_webServices_providers_customerDetail_Binder"
contract="customerDetail_PortType"
name="EMMCRMIntegration_webServices_providers_customerDetail_Port"
/>
</client>
</system.serviceModel>
</configuration>
I would really appreciate your help. I tried for about an hour to fix this but no luck.
I am trying to create a WCF client APP that is consuming a JAVA WS that uses three certificates of which two of them aer for signing and encryption and one is for transport. There is a private key that is installed on the server and a public certificate file was exported from the JKS keystore file. I have installed the public key and keys for signing and encryption into certificate store via MMC under Personal certificates.
Here is My Code from Form:
public Form1()
{
InitializeComponent();
ServicePointManager.SecurityProtocol=SecurityProtocolType.Tls;
referencaServisa.obrtniWsServiceClient klijent = new referencaServisa.SomeServiceClient();
var vs = klijent.Endpoint.Behaviors.Where((i) => i.GetType().Namespace.Contains("VisualStudio"));
klijent.Endpoint.Behaviors.Remove((System.ServiceModel.Description.IEndpointBehavior)vs.Single());
klijent.Endpoint.Address = new System.ServiceModel.EndpointAddress(#"https://213.147.119.174:4444/some-registar-ws/someWsService");
CustomBinding binding = new CustomBinding();
SecurityBindingElement sbe = SecurityBindingElement.CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
AsymmetricSecurityBindingElement asymetricElement=(AsymmetricSecurityBindingElement)sbe;
asymetricElement.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128Rsa15;
asymetricElement.ProtectTokens = true;
asymetricElement.IncludeTimestamp = false;
asymetricElement.SetKeyDerivation(false);
asymetricElement.EnableUnsecuredResponse = true;
asymetricElement.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
asymetricElement.KeyEntropyMode = SecurityKeyEntropyMode.ClientEntropy;
asymetricElement.AllowSerializedSigningTokenOnReply=true;
X509SecurityTokenParameters initiator = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.SubjectKeyIdentifier, SecurityTokenInclusionMode.AlwaysToInitiator);
/*X509SecurityTokenParameters recipient = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.RawDataKeyIdentifier, SecurityTokenInclusionMode.AlwaysToInitiator);
asymetricElement.RecipientTokenParameters = recipient;
asymetricElement.InitiatorTokenParameters = initiator;
asymetricElement.InitiatorTokenParameters.RequireDerivedKeys = false;*/
asymetricElement.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
asymetricElement.LocalClientSettings.IdentityVerifier = new MyIdentityVerifier();
asymetricElement.EndpointSupportingTokenParameters.Signed.Add(
new X509SecurityTokenParameters());
binding.Elements.Clear();
binding.Elements.Add(asymetricElement);
CustomTextMessageBindingElement customTextMessageBindingElement = new CustomTextMessageBindingElement("UTF-8", "text/xml", MessageVersion.Soap11);
binding.Elements.Add(customTextMessageBindingElement);
HttpsTransportBindingElement httpsTransportBindingElement = new HttpsTransportBindingElement
{
RequireClientCertificate=true
};
httpsTransportBindingElement.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
httpsTransportBindingElement.TransferMode = TransferMode.Buffered;
httpsTransportBindingElement.UseDefaultWebProxy = true;
httpsTransportBindingElement.KeepAliveEnabled=true;
httpsTransportBindingElement.AuthenticationScheme = AuthenticationSchemes.Digest;
httpsTransportBindingElement.RequireClientCertificate = true;
binding.Elements.Add(httpsTransportBindingElement);
klijent.Endpoint.Binding = binding;
referencaServisa.statusType status;
string poruka;
referencaServisa.registarskiUlozak[] registarskiUlosci;
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// Begin using the client.
try
{
klijent.Open();
status = klijent.getUlosciByMbo("90445066",false, out poruka, out registarskiUlosci);
referencaServisa.ulozak receivedUlozak = null;
if (status.ToString() == "OK")
{
receivedUlozak = registarskiUlosci[0].aktivnoStanjeUloska.ulozak;
MessageBox.Show(receivedUlozak.vlasnici[0].redniBroj.ToString());
}
MessageBox.Show(status.ToString());
// Close the client.
klijent.Close();
}
catch (ProtocolException ex) { MessageBox.Show(ex.Message); }
}
So I use three certificates one for signing one for encryption and one for SSL transport. I use custom binding for separation of certificates. When I start my app I get an error General security error:
The content type text/xml;charset=UTF-8 of the response message does not match the content type of the binding (text/xml; charset=UTF-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 394 bytes of the response were: '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode xmlns:ns1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">ns1:InvalidSecurity</faultcode><faultstring>An error was discovered processing the <wsse:Security> header (Unsupported key identification)</faultstring></soap:Fault></soap:Body></soap:Envelope>'.
Here is my app.config :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="dasda12312.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="false"/>
</settings>
</system.net>
<system.diagnostics>
<switches>
<add name="Remote.Disable" value="1"/>
</switches>
</system.diagnostics>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="MyClientCredentialsExtension">
<MyClientCredentialsExtension>
<clientCertificate findValue="removed" storeLocation="LocalMachine" x509FindType="FindBySerialNumber" storeName="My" />
<serviceCertificate>
<defaultCertificate findValue="removed" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
</serviceCertificate>
<transportCertificate findValue="removed" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySerialNumber"/>
</MyClientCredentialsExtension>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="cb">
<security authenticationMode="MutualCertificate" requireDerivedKeys="true" includeTimestamp="true"
allowSerializedSigningTokenOnReply="true" securityHeaderLayout="Lax"
defaultAlgorithmSuite="Basic256"
keyEntropyMode="ClientEntropy" requireSecurityContextCancellation="false"
messageProtectionOrder="SignBeforeEncrypt" messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10" />
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
</customBinding>
<client>
<!---->
<endpoint address=""
behaviorConfiguration="MyClientCredentialsExtension" binding="customBinding" bindingConfiguration="cb"
contract="referencaServisa.someWsService"
name="SomeWsServiceImplPort">
</endpoint>
</client>
<extensions>
<behaviorExtensions>
<add name="MyClientCredentialsExtension" type="SEOP.MyClientCredentialsExtensionElement,dasda12312"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>
<applicationSettings>
<dasda12312.Properties.Settings>
<setting name="dasda12312_someReferenca2_someWsService" serializeAs="string">
<value>https://213.147.119.174:4444/some-registar-ws/someWsService</value>
</setting>
</dasda12312.Properties.Settings>
</applicationSettings>
</configuration>
Anyone had similar problem please help me and tell me how to fix this.
Thank you.
Error code :
The type name or alias UnitOfWorkFactory could not be resolved.
Please check your configuration file and verify this type name.
I'm scraping google results / trying to debug for 2 days now, and I didn't find any solution yet.
Mention that "ApplicationService" is being resolved.
I verified the names of assemblies and namespaces many times
I already tried this concepts in the config file: https://stackoverflow.com/a/18671286/3264998 , and other concepts.
I verified the connection to the database.
I tried debugging mode in VS without any succes.
Probably some other stuff that I don't remember right now.
Bellow you have my code, hope it's enough. If there is any other file/info that I've omitted I apologies and I will edit the post immediately.
IApplicationService.cs
using System.Collections.Generic;
using Abc.Project.Domain.Model.DTO;
namespace Abc.Project.Application.Interfaces
{
public interface IApplicationService
{
void AddFile(FileDTO fileDTO);
}
}
ApplicationService.cs
using System.Collections.Generic;
using AutoMapper;
using Microsoft.Practices.Unity;
using Abc.Project.Application.Interfaces;
using Abc.Project.Domain.Model.DTO;
using Abc.Project.Domain.Model.Poco.Entities;
using Abc.Project.Domain.Repository.UnitOfWork;
using Abc.Project.Domain.Unity;
namespace Abc.Project.Application.Services.Global
{
public class ApplicationService : IApplicationService
{
public void AddFile(FileDTO fileDTO)
{
File file = new File
{
Id = fileDTO.ID,
FileObs = fileDTO.FileObs,
Ind = fileDTO.Ind,
Levels = fileDTO.Levels,
};
using (var uow = IoC.Container.Resolve<IUnitOfWorkFactory>().Create())
{
uow.Context.File.Add(file);
uow.Commit();
}
}
}
}
IUnitOfWorkFactory.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Abc.Project.Domain.Repository.UnitOfWork
{
public interface IUnitOfWorkFactory
{
IUnitOfWork Create();
}
}
UnitOfWorkFactory.cs
using System.Data;
using System.Reflection;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Tool.hbm2ddl;
using Abc.Project.Domain.Repository.UnitOfWork;
namespace Abc.Project.DataAccess.NHibernate.UnitOfWork
{
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(c => c.FromConnectionStringWithKey("FilesDB"))
)
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(cfg => new SchemaExport(cfg)
.Create(false, false))
.BuildSessionFactory();
}
public IUnitOfWork Create()
{
UnitOfWork UnitOfWork = new UnitOfWork(CreateSessionFactory().OpenSession());
UnitOfWork.BeginTransaction(IsolationLevel.ReadCommitted);
return UnitOfWork;
}
}
}
App.config
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<connectionStrings>
<add name="FilesDB" providerName="System.Data.SqlClient" connectionString="server=SP2010;database=FilesDB;User ID=sa;Password=password;"/>
</connectionStrings>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<typeAliases>
<!-- Lifetime manager types -->
<typeAlias alias="singlecall" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity"/>
<typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity"/>
<typeAlias alias="external" type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager, Microsoft.Practices.Unity"/>
<typeAlias alias="percall" type="Abc.Project.Domain.Unity.StaticPerCallLifeTimeManager, Abc.Project.Domain.Model"/>
<!-- SERVICE APPLICATION INTERFACES-->
<typeAlias alias="IApplicationService" type="Abc.Project.Application.Interfaces.IApplicationService, Abc.Project.Application.Interfaces"/>
<!-- DOMAIN INTERFACES-->
<typeAlias alias="IUnitOfWorkFactory" type="Abc.Project.Domain.Repository.UnitOfWork.IUnitOfWorkFactory, Abc.Project.Domain.Repository"/>
<!-- CONCRETE CLASSES-->
<!-- SERVICE APPLICATION-->
<typeAlias alias="ApplicationService" type="Abc.Project.Application.Services.Global.ApplicationService, Abc.Project.Application.Services"/>
<!--DATA ACCESS-->
<typeAlias alias="UnitOfWorkFactory" type="Abc.Project.DataAccess.NHibernate.UnitOfWork.UnitOfWorkFactory, Abc.Project.DataAccess.NHibernate"/>
</typeAliases>
<containers>
<container>
<!--<extension type="Interception" />-->
<types>
<type type="IApplicationService" mapTo="ApplicationService">
<lifetime type="singlecall"/>
</type>
<type type="IUnitOfWorkFactory" mapTo="UnitOfWorkFactory">
<lifetime type="singleton"/>
</type>
</types>
</container>
</containers>
</unity>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="Abc.Project.WcfService.WcfServiceAspNetAjaxBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="metadataAndDebug">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<services>
<service name="Abc.Project.WcfService.WcfService" behaviorConfiguration="metadataAndDebug">
<endpoint address="" behaviorConfiguration="Abc.Project.WcfService.WcfServiceAspNetAjaxBehavior" binding="webHttpBinding" contract="Abc.Project.WcfService.WcfService"/>
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
How can I solve this?
English is not my native language; please excuse typing errors.
Use the <alias>-element instead. Here´s a link to the Unity Configuration Schema
<unity>
<alias alias="IUnitOfWorkFactory" type="Abc.Project.Domain.Repository.UnitOfWork.IUnitOfWorkFactory, Abc.Project.Domain.Repository" />
<alias alias="UnitOfWorkFactory" type="Abc.Project.DataAccess.NHibernate.UnitOfWork.UnitOfWorkFactory, Abc.Project.DataAccess.NHibernate"/>
</unity>
<typeAlias>-Element is outdated and depending on your Unity version not supported anymore.
The assembly for UnitOfWorkFactory wasn't referenced
When I attempt to throw a FaultException<T>, if I generate the Message manually, I get correct SOAP message. However, when I throw the FaultException<T> from my method on the server, I do not get a correct SOAP message. The SOAP message has a Header / Action value of http://www.w3.org/2005/08/addressing/soap/fault, and my Body / Fault / Detail element is missing completely.
Please have a look at the important sections of my code.
The Service Contract
[ServiceContract(Namespace = "http://namespace.com/fault")]
public interface IFaultService
{
[OperationContract(IsOneWay = false)]
[FaultContract(typeof (MyFault))]
void ThrowFaultException();
}
The implementation
(The message_fault and message are manually created for testing only)
public class FaultService : IFaultService
{
public void ThrowFaultException()
{
var fault = new MyFault("This is from the service");
var fault_exception = new FaultException<MyFault>
(fault,
"Fault Service Reason",
FaultCode.CreateReceiverFaultCode("FaultCodeName","http://namespace.com/fault"),
"http://namespace.com/fault/IFaultService/ThrowFaultExceptionMyFaultFault");
var message_fault = fault_exception.CreateMessageFault();
var message = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, message_fault,
fault_exception.Action);
throw fault_exception;
}
}
The Data Contract
[DataContract(Namespace = "http://namespace.com/fault")]
public class MyFault
{
public MyFault(string Message)
{
this.Message = Message;
}
[DataMember]
public string Message { get; set; }
}
The web.config system.serviceModel section
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBindingNoSecurity">
<security mode="None"/>
</binding>
</wsHttpBinding>
<services>
<service name="FaultService">
<endpoint address="ws"
binding="wsHttpBinding"
bindingConfiguration="wsHttpBindingNoSecurity"
bindingNamespace="http://namespace.com/fault"
contract="IFaultService"
name="ws">
</endpoint>
</service>
</services>
...
</system.serviceModel>
Manually generated SOAP message
{<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://namespace.com/fault/IFaultService/ThrowFaultExceptionMyFaultFault</a:Action>
</s:Header>
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Receiver</s:Value>
<s:Subcode>
<s:Value xmlns:a="http://namespace.com/fault">a:FaultCodeName</s:Value>
</s:Subcode>
</s:Code>
<s:Reason>
<s:Text xml:lang="en-US">Fault Service Reason</s:Text>
</s:Reason>
<s:Detail>
<MyFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://namespace.com/fault">
<Message>This is from the service</Message>
</MyFault>
</s:Detail>
</s:Fault>
</s:Body>
</s:Envelope>}
But the actual SOAP that comes across is
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action>
<a:RelatesTo>urn:uuid:a3587103-953a-43f6-9691-951c21de8418</a:RelatesTo>
<ActivityId CorrelationId="23bf0a82-f4ac-4227-85ab-600f6ffe6a6f" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">a0945fa9-f5a3-4958-8682-097a8315f0dc</ActivityId>
</s:Header>
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Sender</s:Value>
</s:Code>
<s:Reason>
<s:Text xml:lang="en-US">Fault Service Reason</s:Text>
</s:Reason>
</s:Fault>
</s:Body>
</s:Envelope>
Thanks in advance.
Well, chalk this one up to experience...
There was an implementation of IErrorHandler that was being added to the service in code, during the build up of the services for Dependency Injection. That implementation of the ProvideFault method converted all exceptions and faults to the non-generic fault that was returned to the client.
Once that implementation was corrected and the service references refreshed, everything worked as expected.
I have a web service which is behind a reverse proxy like this:
Now what is happening is when I try to add a web reference to test the web service then it says that it is unable to download the wsdl file. That is because when the request is sent it it is https://uat.mywebservice.com/Service/Service.asmx but when it hits the reverse proxy and then tires to download the wsdl and disco files it changes the link to http://myservice.comp.com/Service/Service.asmx?wsdl and this is not the right link as myservice.comp.com is just a name space on reverse proxy.
What is happening is headers in the soap file are getting updated to this namespace instead of the actual host name which is uat.mywebservice.com, I was able to see this using fiddler disco file has incorrect address. I had a worked out by creating a proxy class using wsdl.exe tool and then updated all the incorrect links in that class to right host name.
Is there any way that I can make sure the address remains correct when hitting the reverse proxy.
Incorrect: mywebservice.comp.com
<?xml version="1.0" encoding="utf-8" ?>
<discovery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/disco/">
<contractRef ref="http://mvwebservice.comp.com/Service/Service.asmx?wsdl" docRef="http://mvwebservice.comp.com/Service/Service.asmx" xmlns="http://schemas.xmlsoap.org/disco/scl/" />
<soap address="http://mywebservice.comp.com/Service/Service.asmx" xmlns:q1="http://tempuri.org/" binding="q1:ServiceSoap" xmlns="http://schemas.xmlsoap.org/disco/soap/" />
<soap address="http://mywebservice.comp.com/Service/Service.asmx" xmlns:q2="http://tempuri.org/" binding="q2:ServiceSoap12" xmlns="http://schemas.xmlsoap.org/disco/soap/" />
</discovery>
Correct: uat.mywebservice.com
<?xml version="1.0" encoding="utf-8" ?>
<discovery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/disco/">
<contractRef ref="https://uat.mvwebservice.com/Service/Service.asmx?wsdl" docRef="https://uat.mvwebservice.com/Service/Service.asmx" xmlns="http://schemas.xmlsoap.org/disco/scl/" />
<soap address="https://uat.mywebservice.com/Service/Service.asmx" xmlns:q1="http://tempuri.org/" binding="q1:ServiceSoap" xmlns="http://schemas.xmlsoap.org/disco/soap/" />
<soap address="https://uat.mywebservice.com/Service/Service.asmx" xmlns:q2="http://tempuri.org/" binding="q2:ServiceSoap12" xmlns="http://schemas.xmlsoap.org/disco/soap/" />
</discovery>
What I did to solve a similar problem was to force the webservice to emit the correct headers.
You can do the following:
Create the following class in the App_Code folder:
using System;
using System.Web.Services.Description;
namespace Msdn.Web.Services.Samples
{
/// <summary> Summary description for WSDLReflector </summary>
public class WSDLReflector : SoapExtensionReflector
{
public override void ReflectMethod()
{
//no-op
}
public override void ReflectDescription()
{
ServiceDescription description = ReflectionContext.ServiceDescription;
foreach (Service service in description.Services)
{
foreach (Port port in service.Ports)
{
foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
{
SoapAddressBinding binding = extension as SoapAddressBinding;
if (null != binding)
{
binding.Location = binding.Location.Replace("http://mywebservice.comp.com", "https://uat.mywebservice.com");
}
}
}
}
}
}
}
And add this to web.config:
<webServices>
<diagnostics suppressReturningExceptions="true" />
<soapExtensionReflectorTypes>
<add type="Msdn.Web.Services.Samples.WSDLReflector,App_Code"/>
</soapExtensionReflectorTypes>
</webServices>