Cookies Stripped After Being Set but Before Request - c#

I'm having a problem where I am able to retrieve two cookies from a login call from one web service but both cookies are stripped from any requests made to a different web service.
A little background: I have a Windows service (.NET 4.5) that needs to send data to another companies web service interface. Their interface is made up of a couple different independent web services. To connect I have to call a log in web method from one of their services; I'll call it service A. The log in method returns a Long value made up of DateTime ticks as well as two cookies: a session cookie and an authorization cookie. Both cookies must be included in every request.
If I call any of the methods in service A both cookies are included in the request. Using Fiddler I have been able to verify this. However, if I attempt to call a method in service B, both cookies get stripped from the request call before it is made.
Here are the classes and code I am currently using:
CookieBehavior Class
public sealed class CookieBehavior : IContractBehavior, IEndpointBehavior, IClientMessageInspector
{
#region Private fields
public CookieContainer cookieContainer = new CookieContainer();
#endregion
#region Public constructors
public CookieBehavior()
: this(true)
{
}
public CookieBehavior(Boolean shared)
{
this.Shared = shared;
}
#endregion
#region Public properties
public Boolean Shared
{
get;
private set;
}
#endregion
#region Private methods
private void getCookies(HttpResponseMessageProperty prop, CookieContainer cookieContainer)
{
if (prop != null)
{
String header = prop.Headers[HttpResponseHeader.SetCookie];
if (header != null)
{
String[] cookies = header.Split(',');
var cc = new CookieCollection();
foreach (string cookie in cookies)
{
if (cookie.Contains(";"))
{
cc.Add(new Cookie(cookie.Substring(0, cookie.IndexOf("=")),
cookie.Substring(cookie.IndexOf("=") + 1, cookie.IndexOf(";") - (cookie.IndexOf("=") + 1))));
}
else
{
cc.Add(new Cookie(cookie.Substring(0, cookie.IndexOf("=")), cookie.Substring(cookie.IndexOf("=") + 1)));
}
}
cookieContainer.Add(new Uri(#"http://tempuri.org"), cc);
}
}
}
private void setCookies(HttpRequestMessageProperty prop, CookieContainer cookieContainer)
{
if (prop != null)
{
prop.Headers.Add(HttpRequestHeader.Cookie, cookieContainer.GetCookieHeader(new Uri(#"http://tempuri.org")));
}
}
#endregion
#region IClientMessageInspector Members
void IClientMessageInspector.AfterReceiveReply(ref Message reply, Object correlationState)
{
if (((this.Shared == true) ? CookieContext.Current.cookieContainer : this.cookieContainer).Count == 0)
{
HttpResponseMessageProperty prop = reply.Properties[HttpResponseMessageProperty.Name.ToString()] as HttpResponseMessageProperty;
this.getCookies(prop, (this.Shared == true) ? CookieContext.Current.cookieContainer : this.cookieContainer);
}
}
Object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
{
HttpRequestMessageProperty prop = null;
if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name.ToString()))
prop = request.Properties[HttpRequestMessageProperty.Name.ToString()] as HttpRequestMessageProperty;
else
prop = new HttpRequestMessageProperty();
this.setCookies(prop, (this.Shared == true) ? CookieContext.Current.cookieContainer : this.cookieContainer);
return (null);
}
#endregion
#region IEndpointBehavior Members
void IEndpointBehavior.AddBindingParameters(ServiceEndpoint serviceEndpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior)
{
behavior.MessageInspectors.Add(this);
}
void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
{
}
void IEndpointBehavior.Validate(ServiceEndpoint serviceEndpoint)
{
}
#endregion
#region IContractBehavior Members
void IContractBehavior.AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
endpoint.Behaviors.Add(this);
}
void IContractBehavior.ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
}
void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
#endregion
}
CookieContext Class
public class CookieContext : IDisposable
{
#region Internal fields
internal CookieContainer cookieContainer = new CookieContainer();
#endregion
#region Private static fields
[ThreadStatic]
private static CookieContext current = null;
#endregion
#region Public static constructor
public CookieContext()
{
current = this;
}
#endregion
#region Public static properties
public static CookieContext Current
{
get
{
return (current);
}
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
this.cookieContainer.SetCookies(new Uri(#"http://tempuri.org"), String.Empty);
this.cookieContainer = null;
current = null;
}
#endregion
}
My Code
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
using (var cookieCtx = new CookieContext())
{
ServiceA.ServiceASoapClient serviceA_req = new ServiceA.ServiceASoapClient();
ServiceB.ServiceBSoapClient serviceB_req = new ServiceB.ServiceBSoapClient();
var cookieBhr = new CookieBehavior(true);
serviceA_req.Endpoint.EndpointBehaviors.Add(cookieBhr);
serviceB_req.Endpoint.EndpointBehaviors.Add(cookieBhr);
long? loginTicks = serviceA_req.InterfaceLogin();
if (loginTicks.HasValue)
{
// Get/Set data for request call
serviceB_resp = serviceB_req.SendData(fooBar);
}
}
Debugging my application has shown that both cookie headers are correctly set from the request yet they are stripped prior to the service B request.
Why would the both cookies get stripped from the second request?

Related

C# .NET Core SOAP Client basic auth header not set

I have a client generated from a WSDL file and uses this in a .NET core 3.1 project. I can't set the Authorization header through ClientCredentials and a BasicHttp(s)Binding. I used hookbin to see my request. This is my code:
BasicHttpsBinding binding= new BasicHttpsBinding();
//for http
//binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress endpoint = new EndpointAddress("https://hookb.in/...");
var soapClient = new RandomServiceClient(binding, endpoint);
soapClient.ClientCredentials.UserName.UserName = "user";
soapClient.ClientCredentials.UserName.Password = "bla";
soapClient.CallServiceMethod(new Request { Foo = "Bar" });
I already tried using other Bindings like WSHttpBinding like the Microsoft documentation suggests: https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-basic-authentication
What am i doing wrong?
Thanks to: https://stackoverflow.com/a/60714907/9124424
I found a solution, but i still wonder why the code in my question does not work
So you need to add an IClientMessageInspector and an IEndpointBehavior
public class AddHttpHeaderMessageEndpointBehavior : IEndpointBehavior
{
private readonly IClientMessageInspector _httpHeaderMessageInspector;
public AddHttpHeaderMessageEndpointBehavior(Dictionary<string, string> headers)
{
_httpHeaderMessageInspector = new HttpHeaderMessageInspector(headers);
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(_httpHeaderMessageInspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
public class HttpHeaderMessageInspector : IClientMessageInspector
{
private readonly Dictionary<string, string> _headers;
public HttpHeaderMessageInspector(Dictionary<string, string> headers)
{
_headers = headers;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if (request.Properties.Count == 0 || request.Properties[HttpRequestMessageProperty.Name] == null)
{
request.Properties.Add(HttpRequestMessageProperty.Name, new HttpRequestMessageProperty());
}
var headersCollection = ((HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]).Headers;
foreach (var header in _headers) headersCollection[header.Key] = header.Value;
return null;
}
}
And then you can add this IEndpointBehavior to the Endpoint in the client instance
BasicHttpsBinding binding= new BasicHttpsBinding();
//for http
//binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress endpoint = new EndpointAddress("https://hookb.in/...");
var soapClient = new RandomServiceClient(binding, endpoint);
var headers = new Dictionary<string, string>
{
{"Authorization", $"Basic --INSERT TOKEN--"}
}));
var behavior = new AddHttpHeaderMessageEndpointBehavior(headers);
soapClient.Endpoint.EndpointBehaviors.Add(behavior);
soapClient.CallServiceMethod(new Request { Foo = "Bar" });
For me Stutje's solution works perfect, except:
needed to remove binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;, otherwise it asking to set credentials directly.
set binding.Security.Mode = BasicHttpSecurityMode.Transport; to use https

Passing Parameters to WCF constructor

I have a WCF service in c#, that I would like to pass in some parameters upon initialization. Now the error I get is service must be parameter less.
I have read some articles online regarding dependency injection etc. But i'm not sure if that's what i want and have tried a few things and can't seem to get it to work.
I'm also calling it from x++ ax 2012. using ref=AifUtil::createServiceClient(clientType);
to create my service reference, but would like to pass in some parameters upon initial construction of the object. Any simple ideas how to do this ?
You can't use parameterised constructors directly because of WCF default behaviours. However it is possible to do that with using implementaton of ServiceHostFactory, ServiceHost and IInstanceProvider.
Look at this: How do I pass values to the constructor on my wcf service?
EDIT: Added example codes from the link:
Given a service with this constructor signature:
public MyService(IDependency dep)
Here's an example that can spin up MyService:
public class MyServiceHostFactory : ServiceHostFactory
{
private readonly IDependency dep;
public MyServiceHostFactory()
{
this.dep = new MyClass();
}
protected override ServiceHost CreateServiceHost(Type serviceType,
Uri[] baseAddresses)
{
return new MyServiceHost(this.dep, serviceType, baseAddresses);
}
}
public class MyServiceHost : ServiceHost
{
public MyServiceHost(IDependency dep, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
if (dep == null)
{
throw new ArgumentNullException("dep");
}
foreach (var cd in this.ImplementedContracts.Values)
{
cd.Behaviors.Add(new MyInstanceProvider(dep));
}
}
}
public class MyInstanceProvider : IInstanceProvider, IContractBehavior
{
private readonly IDependency dep;
public MyInstanceProvider(IDependency dep)
{
if (dep == null)
{
throw new ArgumentNullException("dep");
}
this.dep = dep;
}
#region IInstanceProvider Members
public object GetInstance(InstanceContext instanceContext, Message message)
{
return this.GetInstance(instanceContext);
}
public object GetInstance(InstanceContext instanceContext)
{
return new MyService(this.dep);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
var disposable = instance as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
#endregion
#region IContractBehavior Members
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.InstanceProvider = this;
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
#endregion
}
Register MyServiceHostFactory in your MyService.svc file, or use MyServiceHost directly in code for self-hosting scenarios.
For self-hosted WCF services such as the console, we can initialize the passed parameters directly in the service host life cycle event, or perform specific actions before the service starts.
For the WCF service is hosted in WCF, this feature could be completed by the service host factory property.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/extending/extending-hosting-using-servicehostfactory
https://blogs.msdn.microsoft.com/carlosfigueira/2011/06/13/wcf-extensibility-servicehostfactory/
Here is a detailed example related to authenticating the client with Asp.net membership provider, before the service running, we seed some data in the database.
Svc markup.
<%# ServiceHost Language="C#" Debug="true" Factory="WcfService2.CalculatorServiceHostFactory" Service="WcfService2.Service1" CodeBehind="Service1.svc.cs" %>
Factory.
public class CalculatorServiceHostFactory : ServiceHostFactoryBase
{
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
return new CalculatorServiceHost(baseAddresses);
}
}
class CalculatorServiceHost : ServiceHost
{
#region CalculatorServiceHost Constructor
/// <summary>
/// Constructs a CalculatorServiceHost. Calls into SetupUsersAndroles to
/// set up the user and roles that the CalculatorService allows
/// </summary>
public CalculatorServiceHost(params Uri[] addresses)
: base(typeof(Service1), addresses)
{
SetupUsersAndRoles();
}
#endregion
/// <summary>
/// Sets up the user and roles that the CalculatorService allows
/// </summary>
internal static void SetupUsersAndRoles()
{
// Create some arrays for membership and role data
string[] users = { "Alice", "Bob", "Charlie" };
string[] emails = { "alice#example.org", "bob#example.org", "charlie#example.org" };
string[] passwords = { "ecilA-123", "treboR-456", "eilrahC-789" };
string[] roles = { "Super Users", "Registered Users", "Users" };
// Clear out existing user information and add fresh user information
for (int i = 0; i < emails.Length; i++)
{
if (Membership.GetUserNameByEmail(emails[i]) != null)
Membership.DeleteUser(users[i], true);
Membership.CreateUser(users[i], passwords[i], emails[i]);
}
// Clear out existing role information and add fresh role information
// This puts Alice, Bob and Charlie in the Users Role, Alice and Bob
// in the Registered Users Role and just Alice in the Super Users Role.
for (int i = 0; i < roles.Length; i++)
{
if (Roles.RoleExists(roles[i]))
{
foreach (string u in Roles.GetUsersInRole(roles[i]))
Roles.RemoveUserFromRole(u, roles[i]);
Roles.DeleteRole(roles[i]);
}
Roles.CreateRole(roles[i]);
string[] userstoadd = new string[i + 1];
for (int j = 0; j < userstoadd.Length; j++)
userstoadd[j] = users[j];
Roles.AddUsersToRole(userstoadd, roles[i]);
}
}
}
Official sample.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-use-the-aspnet-membership-provider
Feel free to let me know if there is anything I can help with.

Hadler Error EndPoint in my host - WCF - Behaviour

A few days ago I opened a question if I succeed with the answers. I had not focused the question well, and now with something more knowledge I ask again.
I need to capture the errors of all my endpoints to have them included in the same site. The idea is to add a behavior to these endpoints.
namespace SIPE.Search.Helpers
{
/// <summary>
/// Implements methods that can be used to extend run-time behavior for an endpoint in either a client application.
/// </summary>
public class ExternalClientBehavior : BehaviorExtensionElement
{
protected override object CreateBehavior()
{
return new ExternalClientBehaviorClass();
}
public override Type BehaviorType
{
get
{
return typeof(ExternalClientBehaviorClass);
}
}
/// <summary>
/// JSON REST[GET] Converter Behavior
/// </summary>
private class ExternalClientBehaviorClass : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
ExternalClientMessageInspector clientInspector = new ExternalClientMessageInspector(endpoint);
clientRuntime.MessageInspectors.Add(clientInspector);
foreach (ClientOperation op in clientRuntime.Operations)
{
op.ParameterInspectors.Add(clientInspector);
}
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
//("Behavior not supported on the consumer side!");
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
}
}
Now I know that it will never enter my ApplyDispatchBehaviour if the client does not implement my behaviour, and this will NEVER happen, since they are external providers and I do not have access to the code.
Also, my first error does not even leave my code, since I'm causing a NOT FOUND error.
I have found many similar sources with my problem without solution. I have found by several sites to add the following in ApplyClientBehaviour:
IErrorHandler errorHandler = new CustomErrorHandler();
clientRuntime.CallbackDispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(errorHandler);
But this does not work.
Other sources that happened to me: https://riptutorial.com/csharp/example/5460/implementing-ierrorhandler-for-wcf-services
It is NOT a solution, since it is for Services Behavior. I need to do it in EndPoint Behavior.
Thank you
Please refer to the following example.
Server side.
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("http://localhost:1100");
BasicHttpBinding binding = new BasicHttpBinding();
using (ServiceHost sh = new ServiceHost(typeof(MyService), uri))
{
ServiceEndpoint se = sh.AddServiceEndpoint(typeof(IService), binding, "");
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri("http://localhost:1100/mex");
sh.Description.Behaviors.Add(smb);
}
MyEndpointBehavior bhv = new MyEndpointBehavior();
se.EndpointBehaviors.Add(bhv);
sh.Open();
Console.WriteLine("service is ready");
Console.ReadKey();
sh.Close();
}
}
}
[ServiceContract(ConfigurationName = "isv")]
public interface IService
{
[OperationContract]
string Delete(int value);
[OperationContract]
void UpdateAll();
}
[ServiceBehavior(ConfigurationName = "sv")]
public class MyService : IService
{
public string Delete(int value)
{
if (value <= 0)
{
throw new ArgumentException("Parameter should be greater than 0");
}
return "Hello";
}
public void UpdateAll()
{
throw new InvalidOperationException("Operation exception");
}
}
public class MyCustomErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
FaultException faultException = new FaultException(error.Message);
MessageFault messageFault = faultException.CreateMessageFault();
fault = Message.CreateMessage(version, messageFault, error.Message);
}
}
public class MyEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
return;
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
MyCustomErrorHandler myCustomErrorHandler = new MyCustomErrorHandler();
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(myCustomErrorHandler);
}
public void Validate(ServiceEndpoint endpoint)
{
return;
}
}
Client.
static void Main(string[] args)
{
ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
try
{
client.Delete(-3);
}
catch (FaultException fault)
{
Console.WriteLine(fault.Reason.GetMatchingTranslation().Text);
}
}
Result.
Feel free to let me know if there is anything I can help with.

How to pass username and password to the SOAP header of a Web Service Call from C#?

I want to write a C# code which calls a (remote) web service in another machine. For this I have to pass username and password in the SOAP header of the call.
I would like to know an example of code to make this in C#.
the produced XML should be like :
<env:Header>
<ns1:Security>
<ns1:UsernameToken>
<ns1:Username>XXXXXXXXXXXXXXXX</ns1:Username>
<ns1:Password>YYYYYYYYYYYYYYYY</ns1:Password>
</ns1:UsernameToken>
</ns1:Security>
</env:Header>
Thanks in advance
J.
Are many ways to do that. The CustomBinding is more flexible because it allow more controll, for that i propose you with that. Pasing header to endpoint is a simple way:
// binding
var binding = new CustomBinding();
binding.Elements.Clear();
binding.Elements.Add(new TextMessageEncodingBindingElement{MessageVersion = MessageVersion.Soap12});
binding.Elements.Add(new HttpTransportBindingElement{MaxReceivedMessageSize = 20000000,});
// endpoint
var endpoint = new EndpointAddress(new Uri(listeningUri), new MySecurityHeader())
var client = new Client(binding, endpoint);
client.SomeMethod();
where MySecurityHeader is an AddressHeader, for example:
public class MySecurityHeader : AddressHeader
{
public override string Name
{
get { return "Security"; }
}
public override string Namespace
{
get { return "<provide the appropiate namespace>"; }
}
protected override void OnWriteAddressHeaderContents(System.Xml.XmlDictionaryWriter writer)
{
// here you do what you want
writer.WriteRaw(String.Format(#"
<UsernameToken xmlns=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"">
<Username>user</Username>
<Password Type=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"">pass</Password>
</UsernameToken>").Trim());
}
}
this is an example using an IEndpointAdress
var customBinding = new CustomBinding();
customBinding.Elements.Add(new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.Soap12, });
customBinding.Elements.Add(new HttpTransportBindingElement { MaxReceivedMessageSize = 20000000, });
var endpointAddres = new EndpointAddress(listeningUri);
var client = new Client(customBinding, endpointAddres);
// add my own IEndpointBehavior
client.ChannelFactory.Endpoint.Behaviors.Add(new CustomBehavior());
client.SomeMethod();
and this is the CustomBehavior definition
public class CustomBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
var inspector = new CustomMessageInspector();
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{}
public void Validate(ServiceEndpoint endpoint)
{}
}
public class CustomMessageInspector : IClientMessageInspector
{
public void AfterReceiveReply(ref Message reply, object correlationState)
{}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
request.Headers.Add(new MyMessageHeader());
return null;
}
}
public class MyMessageHeader : MessageHeader
{
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteRaw(String.Format(#"
<UsernameToken xmlns=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"">
<Username>user</Username>
<Password Type=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"">pass</Password>
</UsernameToken>").Trim());
}
public override string Name
{
get { return "MyHeaderName"; }
}
public override string Namespace
{
get { return "MyHeaderNamespace"; }
}
}
Note you have control before send the request and after receive your reply.
I hope this resolve your issue, if you have some problems with this yust ask me.

Need example on implementing MessageHeaders.WriteHeaderContents

I have a custom header stored in a "string" variable, I need to replace the header of a outgoing SOAP request from my WCF client with the header in the "string" type variable. Based on research I see that implementing the MessageHeaders.WriteHeaderContents can work but this method accepts only XmlDictionaryWriter or XmlWriter types as input. I have a string input. How do I code in C# ..
Message headers are a SOAP concept, and SOAP requests are XML documents, so you really need some XML-ness there. But for your scenario, you actually don't need to override MessageHeaders, you can use an inspector and simply replace the header at that point, as shown in the example below (the conversion to XML will be done by the MessageHeader class).
public class StackOverflow_7141998
{
[MessageContract]
public class MyMC
{
[MessageHeader(Name = "MyHeader", Namespace = "http://my.namespace.com")]
public string HeaderValue { get; set; }
[MessageBodyMember(Name = "MyBody", Namespace = "http://my.namespace.com")]
public string BodyValue { get; set; }
}
[ServiceContract]
public interface ITest
{
[OperationContract]
void Process(MyMC mc);
}
public class Service : ITest
{
public void Process(MyMC mc)
{
Console.WriteLine("Header value: {0}", mc.HeaderValue);
}
}
public class MyInspector : IEndpointBehavior, IClientMessageInspector
{
public string NewHeaderValue { get; set; }
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(this);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
int originalIndex = request.Headers.FindHeader("MyHeader", "http://my.namespace.com");
if (originalIndex >= 0)
{
request.Headers.Insert(originalIndex, MessageHeader.CreateHeader("MyHeader", "http://my.namespace.com", this.NewHeaderValue));
request.Headers.RemoveAt(originalIndex + 1);
}
return null;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), new WSHttpBinding(), "");
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new WSHttpBinding(), new EndpointAddress(baseAddress));
MyInspector inspector = new MyInspector { NewHeaderValue = "Modified header value" };
factory.Endpoint.Behaviors.Add(inspector);
ITest proxy = factory.CreateChannel();
proxy.Process(new MyMC { HeaderValue = "Original header value", BodyValue = "The body" });
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

Categories