Multiple appdomains in Web API 2 - c#

I'm trying to move a Web project from an IIS hosting to a self hosting structure. I'm using Owin and Web API 2.
It appears that this code:
using (WebApp.Start<Startup>(url))
{
bla...
}
creates a AppDomain (with ID == 1).
Edit: This API is a new interface for accessing data for an already existing software ("only" a few millions lines of code), which means that I can't really do what I want. A "user" is actually more of an "account", which means that I technically can have hundreds of clients connected as the same "user".
End of edit
The problem I'm having is the following: when a client logs in, I create an AppDomain to load its static data. As the same account can have several sessions at the same time (or example the same user connected on his smartphone + computer), I have to make a difference between Session and AppDomain.
So, all my Controllers are called within the AppDomain of the user calling the API, all Services too.
BUT, the Web API 2 seems to add a serialization layer after each Controller. And this serialization layer occurs outside the scope of all the AppDomains I have created manually: it is in the AppDomain with ID == 1.
As the serialization sometimes needs access to the staticdata of the user, I end up having quite frequently serialization errors.
I'm looking for a way to either skip the additional serialization induced by Web API 2 or to compel this serialization to occur within a specific AppDomain.
I haven't found any hint for either ideas in the documentation of the .Net packages I'm using nor in the already asked questions.
Any idea (even a workaround) would be greatly appreciated =)
Thanks for any contribution ;)

The problem really came from a static class (thus defined at an AppDomain level) containing A LOT of information, and used in a few getters of properties throughout the code (I know it's a bad practice, but unfortunately I can't change that right now).
The solution I finally come up with is to kind of serialize everything manually in the created AppDomains, thus solving the problem.

Related

Razorengine unique template name from hashed (sha1) template?

I have two entirely separate web (api) services.
One resembles the business case (bc) and the other's only concern is sending (and building) e-mails (ms).
So basically the BC sends all relevant data to the mail service.
BC ===== { Sender, Receipient, Subject, Template, Model } =====> MS
The mail service takes the template (razor template) and the model and builds the mail's content. It does the same with the subject which may also be a razor template.
The question now is... in order for razorengine to work properly... I need to specify unique names for my mail templates and I'd prefer not to trust the business case with this task. Because the client may choose a name which is already in use by another client (business case).
My solution right now looks like this:
string uniqueTemplateName = sha1(template); // bad idea?
string result = _razorEngineService.RunCompile(template, uniqueTemplateName, null, (object)model);
Using sha1(template) should do the trick, right? Are there any drawbacks to this?
You actually have several problems here depending on your requirements.
Initially it seemed like "clientname/templatename" would be a fit.
Usually you just use the path where the template came from (full directory path, database id).
Any kind of hash completely defeats the purpose of the caching layer for you to be able to notice when you need to recycle the current AppDomain because of stale templates. The default CachingProvider will always use the cached entry and changes will be ignored (no recompiles). But you can customize that to your needs. For example you could implement a strategy like: If a single template is edited more than 10 times the AppDomain is recycled. One can achieve this by implementing an ITemplateManager and an ICachingProvider and some AppDomain recycle code. How to do that is a bit out of scope for the question you asked, but you can look at the existing implementations.
This AppDomain recycle stuff is hard and defeating it with a hash seems like an easy solution, but if you have the requirement of changing template you need to think about it, because we can't abstract that away from you (because loaded assemblies cannot be unloaded). And depending on your users and your environment you might get into a situation where users can start a DOS attack to your service by filling up your memory. If you are fine with the performance you can look at the isolation API as well. With isolation you can use very simple approach like recycle the AppDomain every 1000 compiles (you still need to implement the notification yourself with a custom ICachingProvider or even simpler just count the number of times you are using RunCompile).
TL;DR Drawbacks:
Collisions (see the comment of Eric Lippert)
Unable to find/notice stale templates
-> DOS situations
Hope this helps,
matthid (Disclosure: A RazorEngine Contributor)

In C#, how can I get the name of the calling project from within a referenced project?

I have three projects: My.Business, My.WebSite and My.WebService
I need my logging class to be able to identify when a request is made from the website versus the web service. I used to have the web service running as a separate application underneath the web site, so I'd just use different config files, which worked fine. But I want the web service now to run under the same application.
If I could figure out if the request was coming from My.WebSite or My.WebService, I'd be set, but I'm not sure how to do this.
Assembly.GetExecutingAssembly() returns back My.Business
Assembly.GetEntryAssembly() is null
I could check the StackTrace, but that seems sloppy and how for back would I have to go? Especially because the logging may be triggered by code in My.Business that was originally invoked from one of the other projects.
Since the web service requests end in ".asmx", the following concept works, but it just doesn't feel right.
return HttpContext.Current.Request.Path.IndexOf(".asmx") >= 0 ? "My.WebService" : "My.WebSite";
Thanks!
You should be able to use Assembly.GetCallingAssembly():
return Assembly.GetCallingAssembly().FullName;
This will return the assembly that invoked the current executing method, so you can capture whoever is calling into your My.Business assembly that way.
With that said, I tend to agree with the comment above by Meirion Hughes. You might like to consider passing in any info that is required to your logging class, especially if it is likely to be used across more applications in the future.
this.GetType().Assembly.FullName will give you the name of the assembly name for the current class.

Designing an API: Use the Data Layer objects or copy/duplicate?

Struggling with this one today.
Rewriting a web-based application; I would like to do this in such a way that:
All transactions go through a web services API (something like http://api.myapplication.com) so that customers can work with their data the same way that we do / everything they can do through our provided web interface they can also do programmatically
A class library serves as a data layer (SQL + Entity Framework), for a couple of design reasons not related to this question
Problem is, if I choose not to expose the Entity Framework objects through the web service, it's a lot of work to re-create "API" versions of the Entity Framework objects and then write all the "proxy" code to copy properties back and forth.
What's the best practice here? Suck it up and create an API model class for each object, or just use the Entity Framework versions?
Any shortcuts here from those of you who have been down this road and dealt with versioning / backwards compatibility, other headaches?
Edit: After feedback, what makes more sense may be:
Data/Service Layer - DLL used by public web interface directly as well as the Web Services API
Web Services API - almost an exact replica of the Service Layer methods / objects, with API-specific objects and proxy code
I would NOT have the website post data through the web services interface for the API. That way leads to potential performance issues of your main website. Never mind that as soon as you deploy a breaking API change you have to redeploy the main website at the same time. There are reasons why you wouldn't want to be forced to do this.
Instead, your website AND web services should both communicate directly to the underlying business/data layer(s).
Next, don't expose the EF objects themselves. The web service interface should be cleaner than this. In other words it should try and simplify the act of working with your backend as much as possible. Will this require a fair amount of effort on your part? yes. However, it will pay dividends when you have to change the model slightly without impacting currently connected clients.
It depends on project complexity and how long you expect it to live. For small, short living projects you can share domain objects across all layer's. But if it's big project, and you expect it to exist, work well, and update for next 5 years....
In my current project (which is big), I first started with shared entities across all layers, then i discovered that I need separate entities for Presentation, and now (6 month's passed) I'm using separate classes for each layer (persistence, service, domain, presentation) and that's not because i'm paranoid or was following some rules, just I couldn't make all work with single set of classes across layers... Make you conclusions..
P.S. There are tools that can help you convert your objects, like Automapper and Value Injecter.
I would just buck up and create an API specifically aimed at the needs of the application. It doesn't make much sense to what amounts to exposing the whole DB layer. Just expose what needs to be exposed in order to make the app work, and nothing else.

Share an instance between multiple projects

I am working in VS 2008 C# and need to share an instance of an object created in one project with another project. I tried creating a static class in project1 and adding it as a link to project2, but the information wasn't saved. The static class was written in project1.
//object o = new object
//project1.staticObject = o
//project2.object = project1.staticObject
When I tried something like above, project2.object would be null. By adding a class as a link, is it creating a new instance of the static class in project2 or is it referencing the same class? If it is referencing the same class, shouldn't any information saved into the static class from project1 be accessible by project2? I know this isn't the most elegant manner of sharing data, but if anyone would help with this problem or provide a better manner of doing it, I would greatly appreciate it.
Thanks in advance.
Projects run in separate processes, so they can't share data in this manner. You'll need to persist the data in another type of store. I recommend using a database (hey, 20 gazillion websites, stock trading apps, airlines, etc can't be wrong).
If you don't want to use a database, you could open an IP connection between instances of the app and have a thread send packets of data to sync back and forth between the applications. Or, in your "server" app, add a web service that each process would call to update and retrieve information.
If you need really high-speed communication between the processes, sockets with a peer or star topology is a good way to go. If you're okay with some latency, having a web service (which works fine even if these aren't web apps) or a database could be a good solution. The right approach depends on your application.
WCF could also solve this problem. It effectively wraps the IP/socket layer and provides some nice object persistence/remote control capabilities, but I find it overly complex for most applications.
To share a single instance of an object among different processes (that's what I think you are intending to do) you need something that will maintain that object's state. You can look at the WCF and how to set up it's behaviour to act as a singleton so essentially every requester gets the same instance across the board.
http://msdn.microsoft.com/en-us/magazine/cc163590.aspx
Creating the link creates only applies to the source code. When you compile each project, it then has that single class definition available in both projects. The process you took does nothing for instances during runtime for sharing.
You can look at WCF or .NET Remoting, although .NET Remoting is now officially replaced by WCF.
If you are talking about sharing the same object between two processes, you can do that, the concept is called memory-mapped files. Here is some starter docs from msdn.
Though the docs and API use the term "FileMapping" quite a bit, you can use it just for sharing memory between two processes.
In .NET 4.0, you can use the System.IO.MemoryMappedFiles namespace. For your case, looks like .NET 3.5, you'll have to use some sort of interop to use the Win API.

C# Web Service and using a variable

I need to create a project for multiple web services using WCF in c#. The web services will be calling other assemblies to perform the core processing. The assemblies will be accessing data from SQL Server. One of the parameters that will be part of every web service method will include the database to use. My problem is how to pass the database parameter to assemblies to use. I can't change all the signatures for all the satellite assemblies to use. I want to reference some kind of variable that the satellite assembles reference. Theses same satellite assemblies are used with a Windows Forms app and an ASP.NET app so I would need to have something that all types of applications could use. Static fields are not good since for one web service call the database could be "X" and for another it would be "Y". Any ideas?
This is the sort of thing that might play nicely with an IoC or DI framework - having some interface that includes the database information, and have it pushed into all the callers for you. Even without IoC, hiding the implementation in an interface sounds like a solid plan.
With your static concept; a [ThreadStatic] might work but is a little hacky (and you need to be religious about cleaning the data between callers), or another option is to squirrel some information away on the Principal, as this is relatively easily configured from both WCF (per-call) and winforms (typically per-process). In either case, be careful about any thread-switching (async, etc). In particular, note that ASP.NET can change threads in the middle of a single page pipeline.

Categories