WCF IIS hosting issue - c#

I am using VSTS2008 + C# + .Net 3.5 to develop a WCF service hosted in IIS 7.0/6.0. I am learning from the following MSDN link,
http://msdn.microsoft.com/en-us/library/ms733766.aspx
My question is, suppose I implement the WCF service inside a class library and compiled into some specific DLL assembly. In the service svc file, seems there is no way to specify the assembly, in the MSDN sample, only full (including namespace) class name is specified. So, how did WCF runtime finds the assembly which contains the actual implementation of the DLL assembly at server side? Even if I put the assembly into bin sub-folder of the virtual directory, and if there are many DLLs in bin sub-directory, how did WCF runtime knows which dll contains the actual implementation for the specific WCF service?

Marc is correct about putting the assembly name after the namespace with a comma to separate it: I can confirm that it worked for my own WCF service when I did that. The "dll" extension was not required.
So it sounds like your error 404.3 is due to something other than that. I'm sure I've had that one before, though I'm unable to reproduce it when I try to now. But I have a feeling it had something to do with the permissions on the folder in IIS - perhaps check to see if opening up the permissions more will fix the problem. I think the relevant users would be the IIS_IUSRS on your own machine, and maybe also other processes like NETWORK SERVICE (though I could be wrong on this).
The other thing that springs to mind is encryption; I found that when my web folders were encrypted (with the standard Vista encryption) they couldn't be accessed properly by IIS and would give errors like this. So if you have encryption on those files/folders, maybe try turning it off.

(not working - I've left this here simply for visibility so other SO users can see what didn't work)
I'd need to check, but I'm fairly certain it follows the usual pattern - so you could also have written "Some.Namespace.Service, Some.Assembly.dll" (or if that fails, try it omitting the .dll from the end).
I seem to recall that there is one minor change to normal here... usually the runtime will respect [assembly:TypeForwardedTo(...)], but I don't think that WCF handles this - but otherwise, standard type/dll strings should work.

Related

Detect calling project type in a .net class library

I'va generated a class library in Dotnet.
Now I have linked this library in various Clients, a console program, a service, am unit test project and a ASP.NET website.
In some parts I need to load certain files (i.e. Excel templates) from disk. In this case the location for the different caller projects is different.
So my question is: What is the best way to find out, which project type is currently using my library?
Detecting the website client is easy, I just need to check if If System.Web.HttpContext.Current is not Nothing. But what about detecting the other clients?
Even if you manage to detect the different types of application now, you can never be sure whether that logic will still work in the future.
I think it's better to not guess and implement another solution, e.g:
use paths which are relative to the current application's root directory, e.g. by using AppDomain.CurrentDomain.BaseDirectory (MSDN)
put the location of your files into the app's config file (in the appSettings section) and read it from your library using ConfigurationManager.AppSettings.Get() (MSDN)

Manually deleting and using a dll in C# web service

I am writing a Web Service in C# and am an outright novice. Please pardon me if what I have asked is dead silly. I have a set of dlls that the Web Service uses. What I want to achieve is as follows:
Let us assume that the dlls are first.dll, second.dll and common.dll
common.dll is referenced in first.dll and second.dll (common.dll contains interfaces that are implemented in first.dll and second.dll)
common.dll has a static dictionary of the types of classes contained in first.dll and second.dll. Classes from this dictionary are instantiated as required.
Whenever I have a new common.dll ready for release, I want to manually delete the common.dll file and replace it with the new release of common.dll while the system is live/running.
Presently, I am getting the following error when I am attempting to perform step 4:
"This action can't be completed because the file is open in vshost32-clr2.exe"
It is so that I am missing something completely?
24/7 availability is not a cheap thing - do you really need one?
One of easy approaches is to re-route traffic to different servers when you upgraded your application. You get both servers running and verified that new one is OK and than switch traffic to go to new one. You can use DNS entries or some software/hardware router to redirect traffic.
If you really want to replace assemblies on the fly you can do that. You may need enough layers of proxy objects and potentially load your final assemblies in custom app-domain. You may be able to get away with simply copying DLL to root folder of Web Site on IIS and hope that app-domain recycle will work correctly and satisfy your "always live" requirement.
Note: "manually delete" and "the system is live/running all the time" should not appear together for the same system... unless you know of a person who can flawlessly perform the same boring tens of steps multiple times at any time of day...
You have to shut down the hosting website. Copy in the new assembly. Then restart the website.

WCF another best practice?

Ok so I have built my WCF service and its functioning great! However, I am starting to implement it into our pre-existing piece of software now and I am instantly running into the question, do I only use the proxy generated code and get rid of the dll that I used initially? Or do I keep both, and make distinctions between the two very obvious?
What I mean by keeping distinctions is, having a ServerUser and a LocalUser property that represent the same user object. However, my LocalUser property would be filled via the dll that the app initally ran with, if the application service is unavailable.
My main reasoning for this thought pattern is that if I remove my dll, I have a single point of failure. If for some reason my ServiceHost is just not up and running, but the DB server is, I would want my users to still be able to do their job. The features that the new WCF implementation utilize are not dependant for employees to do their job. It is more of a convenience in what the WCF service provides. Also, building in this kind of logic to the Service would allow service modifications more readily available in a non IIS hosted environment.
Also, is there a way to build in logic on the service so that when I pull down the proxy code for the client that it just knows to access the DB manually if the ServiceHost is unavailable? If this was a possibility, I think about 90% of all my problems would disappear.
Thank you in advance!
From what you describe it sounds like keeping your existing DLL, i.e. direct access to the DB, would best suit your needs. Having a WCF service adds nothing if, when it fails, you'll just use the DLL anyway.
Ideally you would go with the WCF service completly and offer some kind of redundency to deal with any potenial service issues. Plus, using a service will mean you won't have to deal with any DLL upgrades/deployments.
But, from your question, it sounds like there would be some real issues to deal with should the service not be available, so just do with the DLL.
EDIT: Just read the last part of your question and I don't think that is possible. The proxy code for accessing services is generated when you add the reference to your project. The kind of "dynamic" information you're after would actually require a service.
EDIT: As a follow up to my comment below you could test this by creating a DLL and class, lets call it Class1. Then create a WCF service with a method that will return Class1. Create a client application and add a reference to the service. If you look at the proxy-generated code you should see (hopefully...I'm thinking of this as I type :)) that the method returns Class1, but when you compile it won't be able to find Class1. This is because Class1 does not have the DataContractAttribute which would auto-generate Class1 on the client. So, you have to distribute the shared DLL to the client. Now when the method returns and WCF tries to re-create Class1 it will use the local version in the shared DLL. Your other DLL, which will already be on the client, would use the same shared DLL.

Type Redefinition With WSE Web Service Import

Consider the following Visual Studio project structure
ProjectA.csproj
AClass.cs
ProjectB.csproj
References
ProjectA
Web References
AWebService
AWebService.csproj
References
ProjectA
ReturnAClassViaWebService.asmx
The issue occurs when ProjectB adds the web reference to AWebService and automatically generates all the proxy code for accessing AWebService including a new implementation of AClass. Since all of our other code needs to use the AClass defined in ProjectA, we're forced to convert the AWebService.AClass returned from the service into something we can use.
We're currently considering two solutions, neither of which are ideal.
Manually editing the generated Reference.cs to remove new definitions of AClass
Serializing AWebService.AClass to a stream then deserializing to ProjectA.AClass
Does anyone have any better solutions? This seems like something common enough for other developers to have experienced it.
Ideally we would like to have the proxy code generated in ProjectB to reference ProjectA.AClass rather than generating a whole new implementation.
Our environment is VS 2008 using .NET 2.0.
I have had the same problem that you are describing and I have tried both of the options you specify without being entirely happy about either of them.
The reason we both have this issue is at least partly because the shared-library-between-consumer-and-provider-of-a-web-service-solution is in violation of accepted patterns and practices for web service design. On the consumer side, it should be sufficient to know the interface published in the WSDL.
Still, if you are prepared to accept a tight coupling between your web service provider and web service consumer and you know for certain that your current client will never be replaced by a different client (which might not be capable of referencing the shared library), then I understand why the proposed solution seems like a neat way to structure your app. IMPORTANT NOTE: Can we really honestly answer yes to both of these questions? Probably not.
To recap:
The issue appears when you have classes (e.g. a strongly typed dataset) defined in some sort of shared library (used on both client and server).
Some of your shared classes are used in the interface defined by your web service.
When the web reference is added there are proxy classes defined (for your shared classes) within the web reference namespace.
Due to the different namespaces the proxy class and its actual counterpart in the shared library are incompatible.
Here are four solutions that can be tried if you want to go ahead with the shared library setup:
Don't. Use the proxy class on the client side. This is how it is intendend to be done. It works fine unless you simultaneously want to leverage aspects of the shared library that are not exposed by the web service WSDL.
Implement or use a provided copy/duplication feature of the class (e.g. you could try to Merge() one strongly typed dataset into another). A Cast is obviosuly not possible, and the copy option is usually not a very good solution either since it tends to have undesirable side-effects. E.g. When you Merge a dataset into another, all the rows in the target dataset will be labeled as 'changed'. This could be resurrected with AcceptChanges(), but what if a couple of the received rows were actually changed.
Serialize everything - except for elementary data types - into strings (and back again on the consumer side). Loss of type safety is one important weakness of this approach.
Remove the explicit declaration of the shared class in Reference.cs and strip the namespace from the shared class wherever it is mentioned within Reference.cs. This is probably the best option. You get what you really wanted. The shared class is returned by the web service. The only irritating drawback with this solution is that your modifications to the reference.cs file is lost whenever you update your web reference. Trust me: It can be seriously annoying.
Here is a link to a similar discussion:
You can reuse existing referenced types between the client and service by clicking on the 'Advanced' button on the 'Add Service Reference' form. Make sure the 'Reuse types in referenced assemblies' checkbox is checked and when the service client is generated it should reuse all types from project A.
In past versions this has not always worked correctly and I've had to explicitly select the shared type assemblies by selecting the 'Reuse types in specified referenced assemblies' option and then checking the appropriate assemblies in the list box. However, I just tested this with VS 2008 SP1 and it appears to work as expected. Obviously, you need to make sure that the types that are being used by the service and client projects are both from project A.
Hope that this helps.
We encountered a similar problem with one of our projects. Because we had several dependencies, we ended up creating a circular reference because project 1 required objects from project 2, but project 2 could not be build before project 3, which relied on project 1 to be build.
To solve this problem, we extracted all the public standalone classes from both projects and placed them inside a single librarie. In the end we created something like this:
Framework.Objects
Framework.Interface
Framework.Implementation
WebService
The WebService would be linked to all projects in our case, whereas external parties would only be linking to the objects and interface classes to work with. The actuall implementation was coupled at runtime through reflection.
Hope this helps

Using the LoaderOptimizationAttribute on a WCF service

I have a wcf service that uses the .net System.AddIns framework to load assemblies into a seperate process and app domain. To improve performance I want to enable the Cross-Domain FastPath.
According to the documentation I need to add the LoaderOptimizationAttribute attribute to the main method of my host application. However I do not have a main method as I am using a service.
So is it possible to use the attribute? If not then how can I ensure that the addin assemblies are loaded as domain neutral?
Thanks.
If you are hosting in IIS, you should be gettng "LoaderOptimization(LoaderOptimization.MultiDomainHost)" applied by default, and there seems to be no way to change this that I can find. If you want something else applied, you may need to roll your own host (not that hard for WCF, but certainly not as convenient or feature-rich as IIS hosting).
However, this should load all assemblies as domain-neutral - so it is probably what you want already. Make sure you are not using Assembly.LoadFrom(), as this makes it impossible for appdomains to share the JITed code.

Categories

Resources