WCF host in Windows service, change url dynamically - windows

I want to host a wcf service via windows service. And in client application I want to give feature by which client can chose which which wcf service he want to consume.
Scenario,
Host WCF in windows service on MacA
Host WCF in windows service on MacB, both services are same.
Now client will have option to choose from MacA service or from MacB service.
Thanks,
Mrinal Jaiswal

First of all you have to put the WCF url in the app.config of your client, next on the login form you can ask the user to specify the IP and Port of the service.
Here is a pice of code from one of my projects:
private void btnLogin_Click(object sender, EventArgs e)
{
string url = "net.tcp://" + txtServer.Text + ":" + txtPort.Text + "/NoxService/";
Program.Config.AppSettings.Settings["ServerAddress"].Value = url;
Program.Config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
//set server ip
Program.NoxProxy.Endpoint.Address = new System.ServiceModel.EndpointAddress(ConfigurationManager.AppSettings["ServerAddress"]);
}

Related

How to disable credentials input for HTTPS call to my WCF hosted in windows service

I'm just creating my first WCF project, so I have a lot of deficiencies in knowledge in this field. My problem is that when I'm calling my WCF url in web browser, I have to enter the credentials but I cannot even use my domain name and password, but I have to choose my personal chip card certificate and enter it's password. After that, everything work like a charm.
My final product should be installed on every user workstation in our domain for IT operations purposes only. So there will be some AD authorization after that.
About certificate... We have our own company root CA certificate, and every workstation have it's own certificate which is it's grandchild:
Example of our certificate tree:
COMPANYROOTCA >> COMPANYSUBCA1 >> WORKSTATIONNAME.DOMAIN (this one is used as WCF service cert)
This is what I have right now for hosting the WCF in my Windows service running under NetworkService Account:
serviceHost.Dispose(); //extension for close() and set to null
Uri httpsUrl = new Uri("baseAdress");
serviceHost = new ServiceHost(typeof(Service.myService), httpsUrl);
WSHttpBinding wsHttpBinding = new WSHttpBinding();
wsHttpBinding.Security.Mode = SecurityMode.Transport;
wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
wsHttpBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
WebHttpBinding webHttpBinding = new WebHttpBinding();
webHttpBinding.Security.Mode = WebHttpSecurityMode.Transport;
webHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
webHttpBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
ServiceMetadataBehavior smb = new ServiceMetadataBehavior
{
HttpGetEnabled = false,
HttpsGetEnabled = true,
};
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection collection = store.Certificates;
X509Certificate2 cert = collection.OfType<X509Certificate2>().First(c => c.SubjectName.Name == "CN=WorkstationName.Domain");
store.Close();
serviceHost.Credentials.ServiceCertificate.Certificate = cert;
ServiceThrottlingBehavior throttleBehavior = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 16,
MaxConcurrentInstances = 26,
MaxConcurrentSessions = 10
};
serviceHost.Description.Behaviors.Add(throttleBehavior);
ServiceEndpoint soapEndpoint = serviceHost.AddServiceEndpoint(typeof(Contract.IMyService), wsHttpBinding, "soap");
ServiceEndpoint restEndpoint = serviceHost.AddServiceEndpoint(typeof(Contract.IMyService), webHttpBinding, "rest");
ServiceEndpoint mexEndpoint = serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpsBinding(), "mex");
restEndpoint.Behaviors.Add(new WebHttpBehavior());
tempAdminHost.Open();
So my question is: Is there any way, how to, for example, automaticaly get domain account which use the browser and call the url or any alternative how to still use HTTPS but without putting any credentials?
I didn’t see the way you use the credential to authenticate the client. the client credential type of the two endpoints you use to host the service are None. How does the browser ask you to input the credential? Besides, by default, If the server set up the ClientCredentialType to Windows, the client would use the current user as the credential. The current user’s password and account will be default credential when need to provide a credential.
One more thing to note, if you are simply prompted in the browser to select a certificate instead of the credential(user/password), as follows,
We may have configured the following parameter(clientcertnegotiation parameter).
netsh http add sslcert ipport=127.0.0.1:8000 certhash=c20ed305ea705cc4e36b317af6ce35dc03cfb83d appid={c9670020-5288-47ea-70b3-5a13da258012} clientcertnegotiation=enable
Because the way you use to provide a certificate to encrypt the communication is not correct.
serviceHost.Credentials.ServiceCertificate.Certificate = cert;
We need to bind the certificate to Port.
https://learn.microsoft.com/en-us/windows/desktop/http/add-sslcert
when hosting the service in IIS, we accomplish it by the below UI.
And the parameter configuration depends on the below.
So I suspect the process that binds the certificate to the specified port is completed by IIS. and the parameter should be ignored.
Feel free to let me know if there is anything I can help with.

Exchange Server - Unauthorized

We have an MVC app that connects to the Exchange server. We used to connect to an on premises server using this code to create the service:
if (string.IsNullOrEmpty(Current.UserPassword))
{
throw new UnauthorizedAccessException("Exchange access requires Authentication by Password");
}
return new ExchangeService
{
Credentials = new NetworkCredential(Current.User.LoginName, Current.UserPassword),
Url = new Uri(ConfigurationManager.AppSettings["ExchangeServiceUrl"]),
};
This worked fine, but now our IT department is migrating the Exchange server to the cloud, and some users are on the cloud server while others are on premises. So I changed the code to this:
if (string.IsNullOrEmpty(Current.UserPassword))
{
throw new UnauthorizedAccessException("Exchange access requires Authentication by Password");
}
var user = ConfigurationManager.AppSettings["ExchangeUser"];
var password = ConfigurationManager.AppSettings["ExchangePassword"];
var exchangeService = new ExchangeService(ExchangeVersion.Exchange2010_SP2)
{
Credentials = new NetworkCredential(user, password),
};
exchangeService.AutodiscoverUrl(Current.EmaiLuser + "#calamos.com", RedirectionCallback);
exchangeService.Credentials = new NetworkCredential(Current.EmaiLuser + "#calamos.com", Current.UserPassword);
return exchangeService;
I am using a service account to do the autodiscovery ( for some reason it doesn't work with a regular account) and then I am changing the credentials of the service to the user that logs in, so he can access the inbox. The problem is that , randomly, the server returns "The request failed. The remote server returned an error: (401) Unauthorized.".
I asked the IT department to check the Exchange logs, but there is nothing there about this error, so I don't know how to fix it...
So by cloud do you mean Office365 ?
I am using a service account to do the autodiscovery ( for some reason it doesn't work with a regular account)
For the users in the cloud you need to ensure the request are sent to the cloud servers maybe enable tracing https://msdn.microsoft.com/en-us/library/office/dd633676(v=exchg.80).aspx and then have a look at where the failed requests are being routed. From what you are saying your discovery is going to always point to your internal servers which is why the request will fail for the cloud based users. You need to have a way of identifying the users that are in the cloud and I would suggest you then just use the single Office365 Endpoint (eg you don't need Autodiscover for that) https//outlook.office365.com/EWS/Exchange.asmx

multiple self-hosted webapi on same server

I want to host, mutiple self-hosted webapi's along with the web-site on the same machine / windows 2k8 server. For hosting the website I am using IIS. and for webapi's I would be using self-hosted webapi 2. How do I configure using self-hosted webapi, so that everything can work in sync on same server.
So lets say I will host the website at http://example.com/mysite and I will be hosting the webapi at http://example.com/apiws and http://example.com/apiui
I am using windows service for the configuration. This is how the web-api self hosting looks like as of now - for first webapi.
protected override void OnStart(string[] args)
{
_config = new HttpSelfHostConfiguration(ServiceAddress);
_config.MapHttpAttributeRoutes();
_config.Routes.MapHttpRoute("DefaultApi",
"apiws/{controller}/{id}",
new { id = RouteParameter.Optional });
_server = new HttpSelfHostServer(_config);
_server.OpenAsync().Wait();
}
the configuration is almost same for the second server as well.
My question is having all of them working on the same port, is it possible? are there any issues which might arise? etc?
you are confusing web-api with mvc.
MVC/IIS/websites needs hosting on domain on sub-domain.
webapi are just for listening to the request and providing the data response.

How to communicate with WEB API in Windows Phone?

I am working with push notifications in windows phone. Notification channel uri is changing while re installing the app in the windows mobile. so there is a problem to send notification to the channel url.
By using web service i am storing the url in database.
I want to update the uri if it is changed using device id.
To do that, i have a WEB API method [HTTPGET] to check the deviceid availability in the database. It is developed to return True/False.
Now my question is, How can we communicate with the service and how can we handle the web api bool return type using C# in windows phone?
Thank You.
To communicate with the service with httpget request you have to use HttpClient class
Here how I do:
HttpClient client = new HttpClient();
string result=await client.GetStringAsync(url);
note that the event which call the web service must be declared async, because the httpclient is purely Asynchronous

Call Windows Service from Controller

I have a windows service created and installed. I want to call it from my MVC controller, as I am implementing MSMQ messaging service, so need to call Windows service.
Ideally the windows service should host a WCF service that your web application can contact. From there, it's a matter of creating a client, making the WCF call (to the service) and sending/receiving the information necessary.
Sorry, didn't see MSMQ until later. How about something like:
MessageQueueTransaction msgTx = new MessageQueueTransaction();
MessageQueue msgQ = new MessageQueue(#".\private$\Orders");
msgTx.Begin();
try
{
msgQ.Send("First Message",msgTx);
msgQ.Send("Second Message",msgTx);
msgTx.Commit();
}
catch
{
msgTx.Abort();
}
finally
{
msgQ.Close();
}
Then, of course, have a method of reading the messages in the service.
there is a .net library to do that as push notifications, it's name is signalr

Resources