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.
Related
I have had to make changes to an assembly reference for a project that runs as a service.
Since then I have had trouble getting the thing to run. It seems that somewhere along the execution of this thing it fails and stops the service.
The .dll in question has been deployed to other projects that run as a scheduled task and hasn't caused any issues there.
This post here (stackoverflow services) suggests that all I need to do is stop the service and start it up again having swapped out the dlls, but I get the feeling I am missing something?
Or even better is there a way to see if the executable that the service runs is working, like in task manager?
EDIT:
I can see what is breaking it and it's entityframe work throwing an exception relating to MetaData, I have a "Core" and and "Application" layer to this project, the core handles the data and the EF models, but it seems the metadata between the connection strings is different eg:
metadata=res://*/EntityFramework.AutomaticOrderingEntities.csdl|res://*/EntityFramework.AutomaticOrderingEntities.ssdl|res://*/EntityFramework.AutomaticOrderingEntities.msl;
which is different to the below:
metadata=res://*/EntityFramework.WebstoreEntities.csdl|res://*/EntityFramework.WebstoreEntities.ssdl|res://*/EntityFramework.WebstoreEntities.msl;
They are both the same name and catalog etc in the connection strings, do they have to be the same?
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)
I found a lot of information for saving different kinds of application/user settings in different places but getting confused what could be the best way for me.
My problem has different dimensions:
The application will have some User-Roles (Admin, StandardUser, ...), where every User (based on Windows-Logon) will belong to one role.
The Admin is allowed to setup everything for everyone.
The settings have different categories:
Application settings (should be the same for every user on the computer)
User-Role-specific settings
User-specific settings
The application has several projects where different projects have to access the settings.
(4. The application is written in C#)
I don't want to mention the things that I have read because I don't want to steer your thoughts into a (maybe wrong) direction.
So, how would you handle this scenario?
Thanks a lot!!
Joerg
EDIT 1
Some more things after the first answers that I hope can clarify my question:
my question doesn't focus on the authentication of the users, it focusses on create/edit/save settings
my first attempts for solving the problem were:
using the Visual Studio Settings.Settings file
... doesn't work because I have several projects that have to have access to the settings AND I couldn't find a way to make the ApplicationSettings writeable (they are readonly)
use the ConfigurationManager-Class
... I am not experienced with this one but as far as I understand this class it is just another class that gives me access to my ApplicationSettings (and has the same problems like #1)
... maybe a link to a good tutorial will help
invent something on my own
... I still hope to find something ready-to-use
I guess in this kind of scenarios you probably have a database. When you incorporate users, user rights, etc in there it is probably also a good place to save your application settings.
I always love the database centric solutions, since there are widely available (when you want to create a new UI based on the same system, you can reuse the settings there).
I think the entity–attribute–value model is a good design strategy to consider.
You can create a view with triggers on them hiding system only properties, enabling the admin to change all, and the user to only change theirs.
By your description I'd say you want Role Based Authentication. It's something that has been asked before. I'd go to the link specified in that answer to find an overview and some code samples of how to approach this problem.
Microsoft has done a great job adding some abstractions with the Membership Providers and now the ASP.NET Identity Framework (in case you have a Web Application). Regardless of what you choose to do, database or config files are going to be involved (take a look here to learn how to manage those) and some sort of claim derived system.
Assumption: You already have figured out how you are going to handle roles, and your question is only about storage/retrieval of settings.
Point #3 means you can't use a Settings file for Application and User scoped settings combined with a custom configuration section for holding the role specific settings (optionally encrypted).
My next suggestion would be a WCF endpoint that exposes the settings, either in their entirety (security trimmed contents of Application + User specific + Role specific) or by some sort of dictionary lookup equivalent. Additionally:
The endpoint would need to require Windows Authentication (or possibly Claims) so that it could determine the user specific/role specific part.
Each application would then need to have knowledge of the WCF endpoint, either through configuration or potentially through WCF Discovery.
Update:
Note that WCF doesn't solve your storage question, but it helps with your point #3 - multiple projects that need to use the same settings. A WCF endpoint allows a single project that encapsulates the storage/retrieval of settings to be re-used by multiple clients. WCF can be complicated to read about, but in practice it's pretty easy to setup - you just decorate an interface and host it in IIS. You could also host it yourself in something like a windows service if you were adverse to using IIS, but deploying it to IIS would be a lot easier. You can then consume it in your other applications by adding a Service Reference to your project, and then you call the interface code as if the code was in your own project.
In case you are talking about a single application with multiple class libraries:
What I'm describing above assumes you are making multiple applications that all need to share settings. If you are actually talking about a single application with multiple class library projects, the built-in Settings can still be used - there is just one manual step you need to do to make it work across projects. After adding settings to both your application project and your class library project(s), you should copy the app.config section containing the settings in your class library and copy/paste it into your application's app.config. Visual Studio isn't very clever and it will only sync the class library Settings changes to an app.config within the class library project, even though an app.config for a class library isn't a "real thing", since only the app.config for the application consuming the class library is actually used by default (which is why you need to merge it into your application's app.config).
If you need multiple class libraries (including the main application project) to use the same settings, you could make a dedicated class library project just to hold the settings (note you can add multiple Settings files to this project to make the settings more modular), and then all the other projects could reference the common settings project (to avoid circular dependencies, you wouldn't hold any Settings in the main application project that a class library needed).
Overriding a user's settings
The Settings object has a mechanism you could use to override settings (say, with value's specified by an administrator). When you add a Settings object to your project, it creates a Settings partial class with some example code for wiring into the SettingsLoaded event. In this event, you could load your administrative settings (either through a WCF call, or perhaps from a know location on the file system) and apply any overrides.
Short Version
I have an application which utilizes a plug-in infrastructure. The plug-ins have configurable properties that help them know how to do their job. The plug-ins are grouped into profiles to define how to complete a task, and the profiles are stored in XML files serialized by the DataContractSerializer. The problem is when reading the configuration files, the application deserializing has to have knowledge of all of the plug-ins defined in the configuration file. I'm looking for a way to handle the resolution of unknown plug-ins. See the proposed solution section below for a couple of the ideas I've looked into implementing, but I am open to just about anything (though I'd rather not have to reinvent the application).
Detail
Background
I've developed a sort of Business Process Automation System for internal use for the company I'm currently working for in C# 4. It makes exhaustive use of 'plug-ins' to define everything (from the tasks that are to be performed to the definition of units of work) and relies heavily on a dynamic configuration model which in turn relies on C# 4/DLR dynamic objects to fulfill jobs. It's a little heavy while executing because of its dynamic nature but it works consistently and performs well enough for our needs.
It includes a WinForms configuration UI that uses Reflection extensively to determine the configurable properties/fields of the plug-ins, as well as, the properties/fields that define each unit of work to be processed. The UI is also built on top of the BPA engine so it has a thorough understanding of the (loose) object model put in place that allows the engine to do its job, which, coincidentally, has led to several user experience improvements, such as, ad-hoc job execution and configure-time validation of user input. Again there is room for improvement, however, it seems to do its job.
The configuration UI utilizes the DataContractSerializer to serialize/deserialize the settings specified, so any plug-ins referenced by the configuration must be loaded before (or at the time of) configuration load.
Structure
The BPA engine is implemented as a shared assembly (DLL) which is referenced by the BPA service (a Windows Service), the Configuration UI (WinForms app), and a plug-in tester (Console application version of the Windows Service). Each of the three applications that reference the shared assembly only include the minimum amount of code necessary to perform their specific purpose. Additionally, all plug-ins must reference a very thin assembly which basically just defines the interface(s) that the plugin must implement.
Problem
Because of the extensibility model used in the application, there has always been a requirement that the config UI is run from the same directory (on the same PC) as the Service application. That way the UI always knows about all of the assemblies that the Service knows about so they can be deserialized without running into missing assemblies. Now that we are getting close to roll out of the system, a demand to allow the Configuration UI remotely on any PC in our network has come about from our network admins for security purposes. Typically this wouldn't be a problem if there was always a known set of assemblies to deploy, however, with the ability to extend the application using user built assemblies, there has to be a way to resolve the assemblies from which the plug-ins can be instantiated/used.
Proposed (potentially obvious) Solution
Add a WCF service to the Service application to allow the typical CRUD operations against the configurations which that instance of the service is aware of and rework the configuration UI to act more like SSMS with a Connect/Disconnect model. This doesn't really solve the problem so we would also need to expose some sort of ServiceContract from the Service application to allow querying of the assemblies it knows about/has access to. That's fine and fairly straight forward however the question arises, "When should the UI find out about the assemblies that the Service is aware of?" On connect we could send all of the assemblies from the Service to the UI to ensure that it always knows about all of the assemblies the service does but that gets messy with AppDomain management (potentially unnecessarily) and assembly version conflicts. So I suggested hooking into the AppDomain.AssemblyResolve/AppDomain.TypeResolve events to only download the assemblies that the client isn't aware of yet and only as needed. This doesn't necessarily cleanup the AppDomain management issues but it definitely helps address the version conflicts and related issues.
Question
If you've stuck with me this long I applaud and thank you, but now I'm finally getting to the actual question here. After months of research and finally coming to a conclusion I am wondering if anyone here has had to deal with a similar issue and how you dealt with the pitfalls and shortcomings? Is there a standard way of handling this that I have missed completely, or do you have any recommendations based on how you have seen this successfully handled in the past? Do you see any problems with the proposed approaches or can you offer an alternative?
I'm aware that not everyone lives in my head so please let me know if you need further clarification/explanation. Thanks!
Update
I've given MEF a fair shake and feel that it is too simplistic for my purposes. It's not that it couldn't be bent to handle the plug-in requirements of my application, the problem is doing so would be too cumbersome and dirty to make it feasible. It is a nice suggestion and it has a lot of potential, but in its current state it just isn't there yet.
Any other ideas or feedback on my proposed solutions?
Update
I don't know if the issue I'm encountering is just too localized, if I failed to properly describe what I am trying to achieve, or if this question is just too unreasonably long to be read in its entirety; but the few answers I've received have been subtly helpful enough to help me think through the problem differently and identify some shortcomings in what I am after.
In short, what I'm trying to do is take three applications which in their current state share information (configuration/assemblies) using a common directory structure, and try to make those applications work across a network with minimal impact on usability and architecture.
File shares seem like the obvious answer to this problem (as #SimonMourier proposed in the comments), but using them translates into lack of control and debugability when something goes wrong. I can see them as a viable short term solution, but long term they just don't seem feasible.
tl;dr, but I'm 90% sure you should take a look into MEF.
When I first saw it I was like "aah, another acronym", but you'll see it's very simple, and it's built in into .NET 4. Best of all, it even runs seamlessly on mono and it's a matter of less than an hour (including coffee break) between hearing about it and compiling hello worlds to get used with the features. It's really that simple.
Basically, you "export" something in an assembly and "import" it into another (all via simple attribute decorations), and you choose where to search for it (example, on the applications directory, plug-ins folder, etc).
Edit: what if you try to download and load (and possibly cache) plugins on-the-fly on configuration load?
I think that you could be overlooking a relatively simple solution that derives somewhat from the Microsoft web.config approach:
Have two sections in the config file:
Section 1 contains enough information about the plugin (i.e. name, version) to allow you to load it into an app domain.
Section 2 contains the information serialized by the plugin.
On loading the plugin, pass the information in section 2 and let the plugin deserialize it according to its needs.
Maybe you can divide this problem into two
administrator allow users to download one of predefined configuration (set of libraries) and MEF helps to inject required dependencies
each activity from user should pass through security proxy, plugin modules not allowed call BL directly. Proxy could match custom security attribute and allowed activities.
i.e.
[MyRole(Name = new[] { "Security.Action" })]
void BlockAccount(string accountId){}
[MyRole(Name = new[] { "Manager.Action" })]
void CreateAccount(string userName){}
[MyRole(Name = new[] { "Security.View", "Manager.View" })]
List<> AcountList(Predicate p){}
and allow for AD groups (some abstract description)
corp\securityOperators = "Security.*" //allow calls to all security manipulation
corp\HQmanager = "Manager.View" //allow only view access
corp\Operator = "Manager.*"
I'm not sure I completely understand the problem but I think this situation calls for "type-preserving serialization" - that is, the serialized file contains enough type information to deserialize back to the original object graph without any hints from the calling application as to what types are involved.
I've used Json.NET to do this and I can highly recommend the library for type-preserving serialization of object graphs. It looks like the NetDataContractSerializer can also do this, from the MSDN Remarks
The NetDataContractSerializer differs from the DataContractSerializer in one important way: the NetDataContractSerializer includes CLR type information in the serialized XML, whereas the DataContractSerializer does not. Therefore, the NetDataContractSerializer can be used only if both the serializing and deserializing ends share the same CLR types.
I chose Json.NET because it can serialize POCOs without any special attributes or interfaces. Both Json.NET and the NetDataContractSerializer allow you to use a custom SerializationBinder - in here you could put any logic regarding loading assemblies that may not yet be loaded.
Unfortunately, changing serialization schemes might be the "breaking-est" change to suggest because all your existing files will become incompatible. You might be able to write a conversion utility that deserializes a file using the old method and serializes the resulting object graph using the new method.
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.