I need to change some configuration settings on-the-fly in a Windows Azure project - and they need to be changed via a web service call (updating the application's configuration either via the platform api or the Azure Management site isn't an option here).
The project has multiple web and worker roles - all of which will need to know about the new configuration when it is changed.
The configuration is persisted to durable storage, and it's also cached during runtime in a static variable.
My solution was to create an internal (tcp) endpoint on my roles, and use that to loop through all of the roles and instances within those roles, create a client on the fly, and tell the instance about the new setting. (pretty much identical to: http://msdn.microsoft.com/en-us/gg457891)
At first I started a ServiceHost in the WebRole's RoleEntryPoint... and I was confused why everything seemed to be working fine when I stepped through the communications (the static variables where getting set correctly) - yet when I'd make other webservice calls, the static variable seemed to have "forgotten" what I set it to.
This was the case both locally, and in the Azure staging environment.
At this point I realized that because we're using full-IIS mode, the RoleEntryPoint and the Web Services were running in two separate processes - one in Azure's stub, and one in IIS.
"Not a problem" I said, I'll simply move the line of code which starts the ServiceHost from my RoleEntryPoint into the global.asax - at which point the ServiceHost will have been started in the same process as the rest of the site - and the static variables would be the same ones.
Here's where I'm having a problem; This works great on my local machine running in the dev environment. As soon as I deploy to staging I start getting error emails saying the channel used to connect to the service can't be closed because it's in a "faulted state".
Question:
What's different about Azure vs. Dev environment that is causing this?
How can I fix or workaround the problem?
Does anyone have any general advice on how I should go about obtaining a more descriptive error... do I have to enable full wcf diagnostics in Azure to get this, or is there some other way I can get at the exception details?
Follow-Up:
Via remote desktop i've learned several interesting things:
Non-HTTP Activation isn't installed by default on Azure WebRoles. I believe this can be overcome via a startup script:
start /w pkgmgr /iu:WCF-NonHTTP-Activation;
The website created in IIS by the web role doesn't have the net.tcp protocol enabled by default. I also believe this can be overcome with a startup script:
%systemroot%\system32\inetsrv\appcmd.exe set app "Website Name Here" /enabledProtocols:https,http,net.tcp
I haven't had time to take this all the way, as deadlines have forced me to implement some workarounds temporarily.
Some useful links related to this topic:
http://msdn.microsoft.com/en-us/magazine/cc163357.aspx
http://forums.iis.net/t/1160443.aspx
http://msdn.microsoft.com/en-us/library/ms731053.aspx
http://labs.episerver.com/en/Blogs/Paul-Smith/Dates/2008/6/Hosting-non-HTTP-based-WCF-applications-in-IIS7/
UPDATE (6/27/2011):
Amazingly, someone at Microsoft (whose blog I commented on) actually got me an answer on this.
The Azure & WCF teams updated this post:
http://blogs.msdn.com/b/windowsazure/archive/2011/06/27/hosting-services-with-was-and-iis-on-windows-azure.aspx
The link contains all of the information you need to get going with this.
And a HUGE thanks goes to Yavor Georgiev, the MSFT PM with the win.
It's been quite a while since I've asked the question, and no answers, so let me leave this:
Per my follow-ups in the post, there are ways of making this work... but they are complicated and difficult to implement.
For WORKER ROLES, netTcpBinding works perfectly. No issues here. Go ahead and use it.
For WEB ROLES, you've got problems.But netTcpBinding is what you need to use for exposing internal endpoints. What to do?
Well, here's what I did:
Start netTcpBinding service in your RoleEntryPoint using ServiceHost.
Create standard WCF service in your web role using SOAP / JSON / Whatever you want.
When you receive requests through your netTcpBinding, proxy them along to the WCF service on the loopback adapter.
Properly secure your "internal" WCF service with SSL client certs.
It's not perfect... but it works, and it's not terrible.
I suspect that needing to do this kind of thing isn't super common, and I really can't think of any reason why you'd need to other than to dynamically modify settings at runtime... which means you're not slamming these services like crazy.
Obviously, YMMV.
I had a miserable time getting HTTP working between instances in staging, and gave up when it looked like I needed to mess around with netsh to give my processes permission to listen via an HttpListener (sheesh!). So I switched to TCP via sockets. HTTP just adds overhead in a point-to-point communication scenario like this.
Related
I'm currently working on a WCF service which holds and processes all the data for an application, while a MySql database is used for persistence. The service currently works as a singleton (InstanceContextMode.Single) and supports multiple concurrent calls (ConcurrencyMode.Multiple). I'm not really sure what version of IIS the service is hosted in, but I believe it is IIS 7.5.
The problem is that there are some situations where if an exception occurs (eg.: while releasing ReaderWriterLockSlim locks), the service will be in a unreliable state and data may get corrupted (and written into the database) if users keep calling the service.
Currently I know of two ways of preventing users from calling the service: either closing the InstanceContext object (through OperationContext.Current) or raising an exception in IDispatchMessageInspector.AfterReceiveRequest if the service is in a faulted state. The problem with both of these two ways is that they make the service unavailable until I restart the server/application pool (which I can't, see note below) or re-deploy the service.
Important note: Although I have Full-Trust, the service is currently hosted on a shared server, so I can't restart the server or the entire application pool (if that is possible) because that would restart other people's services as well.
Update:
I tried unloading the AppDomain as #usr suggested, but that doesn't work as well: after unloading it, an exception is raised for every call to the service.
Currently I'm trying to find out what WCF/IIS uses as a condition to decide if the service should be created again. I noticed that in the code generated for the client checks if there is any channel available to communicate with the service; if there isn't, a new one is created. Thus, I tried to close all channels in the service: I tried closing OperationContext.Current.InstanceContext.OutgoingChannels, OperationContext.Current.InstanceContext.IncomingChannels, OperationContext.Current.Channel, and many other properties with "Channel" in their name, all of them with no success.
The way to warm-up anything in IIS prior to version 7.5 is using scheduled console application to ping your web site / services and warm them up. It's not a good fix but it works, it is easy and I saw it on every project which had to deal with this requirement.
Or If you are using IIS 7.5 then
You can use Windows Server AppFabric, it has Auto Stat feature to keep the service always on. But you need to be on IIS 7.5 to install App Fabric.
I have a client where I'm trying to port their code to my machine for development purposes. They built their wcf services using classes and interfaces only - thus no svc files. Almost like you would find with self hosting.
When I run the application, these services are hosted by WcfSvcClient (for debugging purposes) and I can see them starting up. I can however not access these services by pointing my browser to the given urls, nor can I step into that code.
I know this should work, because it works on a client machine - but I cannot tell why it isn't working on my machine other than suspecting it needs a computer which runs on their domain?
The strange thing I've noticed is they declared a host url in the wcf services config file for each service. This url is used when starting WcfSvcClient - but it is not configured anywhere else I can see i.e. not IIS. It just mysteriously exists and I have no idea how to call it, debug it or even under which account it runs. Is this configurable somewhere?
Could someone perhaps point me in the right direction? My knowledge with wcf is very limited. Thanks
Ok so it seems wsHttpBinding does support authentication where the domain the service is running on is relevant. This is it's default behavior. You have to explicitly tell it to not do so, by including:
securityMode=None
in your binding configuration. Not suggested for production.
For more information see this post: WCF slow ServiceHost.Open() call
I have been through WCF and related topics, created my first WCF service. It works fine but the problem is that I don't understand hosting concept.
Different tutorials do different things like some create separate console applications for it to host service then using it in Asp.net app but some doesn't host it in any place and just add reference to another project and use it.
I don't understand that when to host where and why?
Please help me in this issue. I am using Visual studio 2013 with .net 4 and asp.net c#.
Basically, a WCF service needs to be hosted somewhere, so that it can be accessed from somewhere else. There are several ways to do this (and probably more than I know about too), but two of the most simple and common ways are to host the service in IIS Express, or in IIS (Internet Information Server).
IIS Express
The simplest way to achieve the first (IIS Express), is to simply right click the project in Visual Studio, and select View in Browser. That will open a directory listing in your browser, and in that directory you should see a file ending in .svc. Clicking that file should open the service description page with text like:
You have created a service.
To test this service, you will need to create a client (...)
The URL to that page, is in effect the URL clients will need to connect to your service. It should look something like http://localhost:64835/YourServiceName.svc.
That means the service is hosted locally, at port 64835, and accessible for clients at that address. Since this is in IIS Express however, it will no longer be accessible once you've closed Visual Studio, since it only runs as part of it.
IIS proper
Hosting in IIS means your service will be accessible whenever IIS is running. Once installed, it will usually start up when you log in, and run silently in the background. When it is running, you can start your service simply by accessing the correct URL. If it is not running, it might take a few seconds to start it. The next time it is called, it should respond quickly.
Note that in IIS, an application will by default run on port 80, which is the default port checked by browsers and possibly other clients - which means you don't need to specify it as in the example above. The URL will therefor generally be something more simple, like http://localhost/yourservice/yourservice.svc (although you could configure it to another port, or another protocol (say https://.., or something else if you like).
Once configured, and the relevant port is open however, your service should be accessible to the rest of the world.
Note: From the outside world, the URL will be different; it could be something like:
http://123.456.789.123/yourservice/yourservice.svc, if that is your IP address, or
http://yourdomain.com/yourservice/yourservice.svc if you've set up a domain.
I would suggest you consider hosting under two categories:
Self Hosting
IIS Hosting
As per you question "when to host where and why", I would say that you self host a WCF service only during testing. Mostly, self hosting is not used in live/production environments. For production environments use ISS hosting.
Self-hosting would be useful for testing on the local machine and on the intranet, while IIS hosting would be useful over the internet.
However, one must be aware that there is no rule as such regarding the usage of a particular hosting technique in any particular situation. With experience, the developer will be the best judge.
I am relatively green with C# and WCF. I have landed on a project where I am creating self hosted WCF services running as Windows services but am starting to wonder if I should use IIS instead (which we don't currently use) as managing all of these services could eventually get cumbersome.
Despite my best efforts, I have yet to find any definitive information about why I might favor one approach over the other. The services are primarily used for utility stuff like resizing images, retrieving files, etc. and are called by both C# and Java clients.
Thanks
The shortest answer would be 'it depends'. On your requirements. You can self host without problems, but IIS will manage resources more effectively and enable you to fine tune stuff more easily than self-hosted.
For instance, in IIS would be more simple to deploy a new version or remove and old one.
Either way is fine.
Generally, using the builtin IIS hosting capabilities can make deployment and configuration simpler for you. Also you have the activation model of http.sys - which means IIS will start the necessary process for you when an appropriate message arrives.
Clients of any platform can connect to the WCF services regardless whether they are self-hosted or IIS hosted.
ps: how to allow IIS-hosted WCF services to store their configuration data in distinct xxx.config files
I have one WCF service deployed in multiple websites hosted in IIS7 and sometimes (development environemnt) in VS2010.
Often multiple instances are connected to the same database and usually its not a problem as its read-only access, but sometimes (like in logging) I need to uniquely identify instance of the service accessing DB.
Currently I do it by putting special attribute in web.config which I'll later use as a part of primary key, but I do feel its not ideal solution.
I thought about site-name in case its hosted in IIS and machine name + port if its hosted from VS2010.
And here comes the question: How to access info about where the WCF service is deployed and how to do it programmatically from inside of deployed service in c#? Is it at all possible?
Thank you for your suggestions.
Michal
The other day there was a question about how to get the IP address of the WCF server, for logging. This topic might help: How to get IP address of WCF web service
You could also determine if you are running in IIS by finding out what process your app is being run from using System.Diagnostics.Process.GetCurrentProcess(), and see if it is "w3svc.exe", which is what the IIS app pool runs as.
If I understand your question correctly, and I may not, you would like to know were on the server the actual instance is deployed.
If this is the case you can use something like:
(string)AppDomain.CurrentDomain.GetData("APPBASE")
Or I believe this will also work:
AppDomain.CurrentDomain.BaseDirectory;
Using reflection on the assembly or process itself will not work because the running process is the host (IIS, IISExpress, etc), but the two methods I specified should give you the location of the service itself for hosted apps.