I have created a web service that exposes web interface.
the service run in console mode and i see the web interface
public ServiceHost serviceHost = null; public ServiceHost serviceHost = null;;
private readonly TestService s;
public Service()
{
InitializeComponent();
s = new TestService();
}
protected override void OnStart(string[] args)
{
Logger.Info("Start event");
if (serviceHost != null)
{
serviceHost.Close();
}
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
string baseAddress = "http://localhost:8000/Service";
serviceHost = new ServiceHost(typeof(Service1), new System.Uri(baseAddress));
serviceHost.AddServiceEndpoint(typeof(WindowsServiceTemplate.IService1),
new BasicHttpBinding(), baseAddress);
// Check to see if the service host already has a ServiceMetadataBehavior
ServiceMetadataBehavior smb = serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
// If not, add one
if (smb == null)
smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
serviceHost.Description.Behaviors.Add(smb);
// Add MEX endpoint
serviceHost.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex"
);
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
s.Start();
}
protected override void OnStop()
{
Logger.Info("Stop event");
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
s.Stop();
}
protected override void OnShutdown()
{
Logger.Info("Windows is going shutdown");
Stop();
}
public void Start()
{
OnStart(null);
}
}
}
and app.config file :
<system.serviceModel>
<services>
<!-- Note: the service name must match the configuration name for the service implementation. -->
<service name="WindowsServiceTemplate.IService1" behaviorConfiguration="MyServiceTypeBehaviors" >
<!-- Add the following endpoint. -->
<!-- Note: your service must have an http base address to add this endpoint. -->
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mexHttpBinding" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors" >
<!-- Add the following element to your service behavior configuration. -->
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
the configuration file inside app.config (console application project)
i am able to access
http://localhost:8000/Service
but when i try to call the test method
http://localhost:8000/Service/test
i get 404 error.
what am i missing?
Use Webhttpbinding to create the service and webservicehost to host service. I have made a demo, wish it is useful to you.
public partial class Service1 : ServiceBase
{
ServiceHost sh = new ServiceHost(typeof(MyService), new Uri("http://localhost:5900"));
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (sh.State==CommunicationState.Opened)
{
Log("Service open Fail");
}
else
{
WebHttpBinding webHttpBinding = new WebHttpBinding();
ServiceEndpoint se = sh.AddServiceEndpoint(typeof(IService), webHttpBinding, "");
se.EndpointBehaviors.Add(new WebHttpBehavior());
sh.Open();
Log("Service is ready....");
}
}
protected override void OnStop()
{
if (sh.State==CommunicationState.Opened)
{
sh.Close();
Log("Service closed successfully");
}
}
private void Log(string text)
{
using (StreamWriter sw=new StreamWriter(#"D:\log.txt",true))
{
sw.WriteLine($"{text}----Time:{DateTime.Now.ToShortTimeString()}");
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet]
string SayHello();
}
public class MyService : IService
{
public string SayHello()
{
return "Hello Stranger";
}
}
}
Install.
Result.
Here is an official document.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-create-a-basic-wcf-web-http-service
Feel free to let me know if there is anything I can help with.
Related
I am working on a project that makes requests to an API (which I think is WCF). The API requires an X509 certificate as a credential to be able to make requests. After referencing the service for the client and trying to make some requests, I was told that my requests were also missing a UserName header credential in order to authenticate with the API. Is it possible to use both types of credentials in a request and if so would anyone know how to set it up? Sorry if this post is poorly made, this is my first post on this website.
Edit: The username header that I need is at the SOAP message level. A header in the actual SOAP xml request.
This is my program code (with personal info taken out):
using System;
using System.Security.Cryptography.X509Certificates;
using EFM_User_Service_Test.EfmUserService;
namespace EFM_User_Service_Test
{
class Program
{
static void Main(string[] args)
{
X509Certificate2 cert = new X509Certificate2("path to pfx file", "password for file");
EfmUserServiceClient client = new EfmUserServiceClient();
client.ClientCredentials.ClientCertificate.Certificate = cert;
client.ClientCredentials.UserName.UserName = "test#email.com";
client.ClientCredentials.UserName.Password = "test password";
client.Open();
AuthenticateRequestType req = new AuthenticateRequestType();
req.Email = "test#email.com";
req.Password = "test password";
AuthenticateResponseType response = client.AuthenticateUser(req);
string user_id = "";
if (response.Error != null && response.Error.ErrorCode != "0")
{
Console.WriteLine(response.Error.ErrorCode);
Console.WriteLine(response.Error.ErrorText);
} else
{
Console.WriteLine("{0} {1} is now signed in",response.FirstName,response.LastName);
Console.WriteLine("authenticated user id: "+response.UserID);
user_id = response.UserID;
}
GetUserRequestType user_req = new GetUserRequestType();
user_req.UserID = user_id;
var user_response = client.GetUser(user_req);
if (user_response.Error != null)
{
Console.WriteLine("Error Code: "+user_response.Error.ErrorCode);
Console.WriteLine("Error Text: "+user_response.Error.ErrorText);
} else
{
Console.WriteLine(user_response.User.Email);
Console.WriteLine(user_response.User.FirstName);
Console.WriteLine(user_response.User.LastName);
Console.WriteLine(user_response.User.Email);
}
client.Close();
}
}
}
and this is my App.config file for the program which seemed to be automatically generated when I added the service reference
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IEfmUserService" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
<binding name="BasicHttpBinding_IEfmUserService1" messageEncoding="Mtom">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="in place of actual address"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IEfmUserService"
contract="EfmUserService.IEfmUserService" name="BasicHttpBinding_IEfmUserService" />
</client>
</system.serviceModel>
</configuration>
In time I solved this by adding a ServiceBehavior to my app.config file. Note that in my case it's a WPF application.
<configuration>
<system.serviceModel>
<extensions>
<behaviorExtensions>
<!-- Add this -->
<add name="basicAuthenticationBehavior" type="ProjectNamespace.Behaviors.BasicAuthenticationBehaviorExtensionElement, ProjectAssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<behaviors>
<!-- Add this -->
<endpointBehaviors>
<behavior name="basicAuthenticationEndpointBehavior">
<basicAuthenticationBehavior />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<!-- After adding your service reference, your bindings appear here -->
<binding name="DMSinterfaceSoap">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<!-- After adding your service reference, your endpoints appear here -->
<endpoint address="https://soa.example.com/dmsinterface/DMS_service.asmx" binding="basicHttpBinding" behaviorConfiguration="basicAuthenticationEndpointBehavior" ... />
</client>
</system.serviceModel>
<configuration>
The BasicAuthenticationBehaviorExtensionElement looks like this
// Add System.Configuration reference to your ExecutingAssembly
internal class BasicAuthenticationBehaviorExtensionElement : BehaviorExtensionElement
{
/// <summary>Set this property if you want to send specific headers along with each request</summary>
public static TCredentials Credentials { internal get; set; }
public override Type BehaviorType
{
get { return typeof(BasicAuthenticationEndpointBehavior); }
}
protected override object CreateBehavior()
{
return new BasicAuthenticationEndpointBehavior();
}
}
class BasicAuthenticationEndpointBehavior : IEndpointBehavior
{
public BasicAuthenticationEndpointBehavior()
{
}
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)
{
clientRuntime.MessageInspectors.Add(new BasicAuthenticationClientMessageInspector());
}
}
class BasicAuthenticationClientMessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if (BasicAuthenticationBehaviorExtensionElement.Credentials != null)
{
SetRequestHeader(ref request, "USERID", BasicAuthenticationBehaviorExtensionElement.Credentials.Credential.UserName);
SetRequestHeader(ref request, "PSWD", BasicAuthenticationBehaviorExtensionElement.Credentials.Credential.Password);
}
return null;
}
private void SetRequestHeader(ref Message request, string key, string value)
{
object httpRequestMessageObject;
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
{
var httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
if (httpRequestMessage != null)
{
httpRequestMessage.Headers[key] = (value ?? string.Empty);
}
else
{
httpRequestMessage = new HttpRequestMessageProperty();
httpRequestMessage.Headers.Add(key, (value ?? string.Empty));
request.Properties[HttpRequestMessageProperty.Name] = httpRequestMessage;
}
}
else
{
var httpRequestMessage = new HttpRequestMessageProperty();
httpRequestMessage.Headers.Add(key, (value ?? string.Empty));
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
}
}
public void AfterReceiveReply(ref Message reply, object correlationState) { }
}
This adds the authentication header to each request, based on the object stored in static variable.
Then you can send the soap call with the authentication certificate:
#region Get Certificate
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var foundCerts = store.Certificates.Find(X509FindType.FindBySerialNumber, credential.CertificateSerial, false);
if (foundCerts.Count == 0)
throw new Exceptions.NoValidCertificateException();
#endregion
#region Setup client
// Check the App.config for available endpoint configuration names
var client = new MySoapService.DMSinterfaceSoapClient("DMSinterfaceSoap.0");
if (client.Endpoint.Binding is System.ServiceModel.BasicHttpBinding basicBinding)
{
// DMSinterfaceSoap and DMSinterfaceSoap.0 are BasicHttpBindings
// The ClientCredentialType is by default set to None. You should be able to combine HttpClientCredentialTypes but sadly that's not possible.
basicBinding.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Certificate;
}
else if (client.Endpoint.Binding is System.ServiceModel.Channels.CustomBinding customBinding)
{
// DMSinterfaceSoap12 and DMSinterfaceSoap12.0 are CustomBindings
// Whatever additional configuration needs to be performed
}
#endregion
// Set the USERID and PSWD header
BasicAuthenticationBehaviorExtensionElement.Credentials.Credential = credential;
// Send certificate along with request
client.ClientCredentials.ClientCertificate.Certificate = foundCerts[0];
var error = client.GetResult(req, out res);
// Clear the USERID and PSWD header
BasicAuthenticationBehaviorExtensionElement.Credentials.Credential = null;
I have WCF Service hosted on WindowsServiceHost (to communicate WindowsFormsApp <> WindowsServiceHost)
Is there any way get data from WCFService to WindowsServiceHost?
And in other way (set data from WindowsServiceHost to WCFService)
That is what have i done:
I've made a project of WCF Service Library, implemented interface, contracts etc.
I created new project - Windows service and added reference to project from #1 and to System.ServiceModel
Configured app.conf:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="netTcp">
<security mode="Message">
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="mexBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="mexBehavior" name="KSPDJOBWinWCFService.KSPDJOBWinWCFService" >
<endpoint address="KSPDJOBWinWCFService" binding="netTcpBinding" contract="KSPDJOBWinWCFService.IKSPDJOBWinWCFService" bindingConfiguration="netTcp" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8079"/>
<add baseAddress="net.tcp://localhost:8090"/>
</baseAddresses>
</host>
</service>
</services>
I've hosted the WCF in OnStart method of Windows Service
protected override void OnStart(string[] args)
{
host = new ServiceHost(typeof(KSPDJOBWinWCFService.KSPDJOBWinWCFService));
host.Open();
}
Added new solution with WinformsClient app (as WCF Client) and tested communication - all working fine.
The problem is when i send a value from WinFormsClient to WCF Service, and want to read it from Windows Service aplication
Thanks for any Help.
You could hold the WCF service instance in a global variable and work with events. In this sample the WCF Service KSPDJOBWinWCFService exposes an event EventA and the Service Host will handle it. This is the place where you can process the values sent by your WCF Client.
public partial class Service : ServiceBase
{
private ServiceHost _host;
private KSPDJOBWinWCFService _instance;
protected override void OnStart(string[] args)
{
try
{
_instance = new KSPDJOBWinWCFService();
_instance.EventA += HandleEventA;
_host = new ServiceHost(_instance);
_host.Open();
}
catch (Exception ex)
{
// Logging
}
}
public void HandleEventA(object sender, CustomEventArgs e)
{
// do whatever you want here
var localVar = e.Value;
}
protected override void OnStop()
{
try
{
if (_instance != null)
{
_instance.Dispose();
}
_host.Close();
}
catch (Exception ex)
{
// Logging
}
}
}
The WCF Service then fires this event together with the values sent from the WCF client:
public class KSPDJOBWinWCFService : IKSPDJOBWinWCFService
{
public event EventHandler<CustomEventArgs> EventA;
public bool SomeWcfOperation(int value)
{
EventA?.Invoke(this, new CustomEventArgs(value));
return true;
}
}
Create event args that fulfill your needs:
public class CustomEventArgs : EventArgs
{
public int Value { get; set; }
public CustomEventArgs(int value)
{
Value = value;
}
}
You can also expose values with public properties in your WCF Service. But events are also necessary.
I'm new to wcf and learning how to build one, with callbacks. I got an example from the following link:
http://architects.dzone.com/articles/logging-messages-windows-0
I tried implementing the wcf but when i run this in as a test by pressing f5, the test client says:
The service contract is not supported in the wcf client.
Service:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.PerCall)]
public class RatsService : IRatsService
{
public static List<IRatsServiceCallback> callBackList = new List<IRatsServiceCallback>();
public RatsService()
{
}
public void Login()
{
IRatsServiceCallback callback = OperationContext.Current.GetCallbackChannel<IRatsServiceCallback>();
if (!callBackList.Contains(callback))
{
callBackList.Add(callback);
}
}
public void Logout()
{
IRatsServiceCallback callback = OperationContext.Current.GetCallbackChannel<IRatsServiceCallback>();
if (callBackList.Contains(callback))
{
callBackList.Remove(callback);
}
callback.NotifyClient("You are Logged out");
}
public void LogMessages(string Message)
{
foreach (IRatsServiceCallback callback in callBackList)
callback.NotifyClient(Message);
}
Service Interface
[ServiceContract(Name = "IRatsService", SessionMode = SessionMode.Allowed, CallbackContract = typeof(IRatsServiceCallback))]
public interface IRatsService
{
[OperationContract]
void Login();
[OperationContract]
void Logout();
[OperationContract]
void LogMessages(string message);
// TODO: Add your service operations here
}
public interface IRatsServiceCallback
{
[OperationContract]
void NotifyClient(String Message);
}
App.config:
<system.serviceModel>
<services>
<service name="RatsWcf.RatsService">
<endpoint address="" binding="wsDualHttpBinding" contract="RatsWcf.IRatsService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Design_Time_Addresses/RatsWcf/Service1/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
Just wondering what could be wrong here.
There's nothing wrong. The WCF Test Client is a tool which can be used to test many types of WCF services, but not all of them - duplex contracts being one category which is not supported. You'll need to create some sort of client app to test that. In your client app you'll need to write a class which implements the callback interface, so that it can receive the messages initiated by the service.
For example, this is a very simple duplex client / service which uses WCF duplex:
public class DuplexTemplate
{
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface ITest
{
[OperationContract]
string Hello(string text);
}
[ServiceContract(Name = "IReallyWantCallback")]
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void OnHello(string text);
}
public class Service : ITest
{
public string Hello(string text)
{
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
ThreadPool.QueueUserWorkItem(delegate
{
callback.OnHello(text);
});
return text;
}
}
class MyCallback : ICallback
{
AutoResetEvent evt;
public MyCallback(AutoResetEvent evt)
{
this.evt = evt;
}
public void OnHello(string text)
{
Console.WriteLine("[callback] OnHello({0})", text);
evt.Set();
}
}
public static void Test()
{
string baseAddress = "net.tcp://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(ITest), new NetTcpBinding(SecurityMode.None), "");
host.Open();
Console.WriteLine("Host opened");
AutoResetEvent evt = new AutoResetEvent(false);
MyCallback callback = new MyCallback(evt);
DuplexChannelFactory<ITest> factory = new DuplexChannelFactory<ITest>(
new InstanceContext(callback),
new NetTcpBinding(SecurityMode.None),
new EndpointAddress(baseAddress));
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.Hello("foo bar"));
evt.WaitOne();
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
Here is my code..
private IHelloWorld ChannelFactoryWebService()
{
ServiceEndpoint tcpEndPoint = new ServiceEndpoint(
ContractDescription.GetContract(typeof(IHelloWorld)),
new NetTcpBinding(),
new EndpointAddress("net.tcp://myserver/CultureTest/Service.svc"));
ChannelFactory<IHelloWorld> factory = new ChannelFactory<IHelloWorld>(tcpEndPoint);
factory.Endpoint.Behaviors.Add(new CultureBehaviour());
return factory.CreateChannel();
}
[TestMethod] <-------------- FAILING TEST ----
public void ChangingCultureWASViaEndPointTest()
{
IHelloWorld client = ChannelFactoryWebService();
CultureInfo cultureInfo = new CultureInfo("ar-SA");
Thread.CurrentThread.CurrentCulture = cultureInfo;
client.Hello();
string culture = client.HelloCulture();
Assert.AreEqual("ar-SA", culture); <--- fails here.. I get en-US for culture
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, IncludeExceptionDetailInFaults = true)]
public class Server : IHelloWorld
{
#region IHelloWorld Members
public void Hello()
{
Console.WriteLine(string.Format("Hello world from the server in culture {0}", Thread.CurrentThread.CurrentCulture.Name));
}
public string HelloCulture()
{
string cultureName = Thread.CurrentThread.CurrentCulture.Name;
return cultureName;
}
#endregion
}
[ServiceContract]
public interface IHelloWorld
{
[OperationContract]
void Hello();
[OperationContract]
string HelloCulture();
}
public class CultureMessageInspector : IClientMessageInspector, IDispatchMessageInspector
{
private const string HeaderKey = "culture";
#region IDispatchMessageInspector Members
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
int headerIndex = request.Headers.FindHeader(HeaderKey, string.Empty);
if (headerIndex != -1)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo(request.Headers.GetHeader<String>(headerIndex));
}
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
#endregion
#region IClientMessageInspector Members
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
request.Headers.Add(MessageHeader.CreateHeader(HeaderKey, string.Empty, Thread.CurrentThread.CurrentCulture.Name));
return null;
}
#endregion
}
public class CultureBehaviour : IEndpointBehavior
{
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
CultureMessageInspector inspector = new CultureMessageInspector();
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
CultureMessageInspector inspector = new CultureMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}
public void Validate(ServiceEndpoint endpoint)
{
}
#endregion
}
public class CultureBehaviorExtension : BehaviorExtensionElement
{
// BehaviorExtensionElement members
public override Type BehaviorType
{
get { return typeof(CultureBehaviour); }
}
protected override object CreateBehavior()
{
return new CultureBehaviour();
}
}
Web config for the hosting site for Service looks as follows:
<endpointBehaviors>
<behavior name="Default">
<CultureExtension/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="CultureExtension" type="Extension.CultureBehaviorExtension, Extension, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
My question is, inside the following code when I go through the service hosted by website,
I am unable to get the culture value of ar-SA inside the Hello method of the service.
I tried my best to clarify the question here. Please let me know what else needs to be clarified.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, IncludeExceptionDetailInFaults = true)]
public class Server : IHelloWorld
{
#region IHelloWorld Members
public void Hello()
{
<--- problem here unable to get culture value of ar-SA here --->
Console.WriteLine(string.Format("Hello world from the server in culture {0}", Thread.CurrentThread.CurrentCulture.Name));
}
public string HelloCulture()
{
string cultureName = Thread.CurrentThread.CurrentCulture.Name;
Console.WriteLine("**************************hello**********************************");
Console.WriteLine(cultureName);
return cultureName;
}
#endregion
}
Its not really an answer why that particular code doesnt work, but why dont you just sent in the culture string and set it in your method on the WCF service?
Thats the way we usualy do it, or if its an authenticated user, just save it on the user so they can switch to any language regardless of computer config.
I have application based on this tutorial
Method I use to test connection to server (in client app):
public class PBMBService : IService
{
private void btnPing_Click(object sender, EventArgs e)
{
ServiceClient service = new ServiceClient();
tbInfo.Text = service.Ping().Replace("\n", "\r\n");
service.Close();
}
//other methods
}
Service main function:
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8000/PBMB");
ServiceHost selfHost = new ServiceHost(typeof(PBMBService), baseAddress);
try
{
selfHost.AddServiceEndpoint(
typeof(IService),
new WSHttpBinding(),
"PBMBService");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
selfHost.Open();
Console.WriteLine("Serwis gotowy.");
Console.WriteLine("Naciśnij <ENTER> aby zamknąć serwis.");
Console.WriteLine();
Console.ReadLine();
selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("Nastąpił wyjątek: {0}", ce.Message);
selfHost.Abort();
}
}
}
In app.config I have:
<client>
<endpoint address="http://localhost:8000/PBMB/PBMBService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService" contract="IService"
name="WSHttpBinding_IService">
<identity>
<userPrincipalName value="PPC\Pawel" />
</identity>
</endpoint>
</client>
I can change IP from here. But how can I change it during runtime (i.e. read address/IP from file)?
You can replace the service endpoint after you created your client class:
public class PBMBService : IService
{
private void btnPing_Click(object sender, EventArgs e)
{
ServiceClient service = new ServiceClient();
service.Endpoint.Address = new EndpointAddress("http://the.new.address/to/the/service");
tbInfo.Text = service.Ping().Replace("\n", "\r\n");
service.Close();
}
}
You can use the following channel factory:
using System.ServiceModel;
namespace PgAuthentication
{
public class ServiceClientFactory<TChannel> : ChannelFactory<TChannel> where TChannel : class
{
public TChannel Create(string url)
{
return CreateChannel(new BasicHttpBinding { Security = { Mode = BasicHttpSecurityMode.None } }, new EndpointAddress(url));
}
}
}
and you can use this with the following code:
Console.WriteLine(
new ServiceClientFactory<IAuthenticationChannel>()
.Create("http://crm.payamgostar.com/Services/IAuthentication.svc")
.AuthenticateUserNameAndPassWord("o", "123", "o", "123").Success);