How to share code / assemblies
-
Monday, February 20, 2012 11:13 AM
Hello folks,
we are developing multitenant apps, until now WCF services were self hosted in a single Windows
Service whereby we are using WCF Routing to provide different endPoints to services.
Now we rethink our hosting model and we are looking to AppFabric.Our WCF
services could be structured like this:The question is how we share the code/ assemblies for different services.
I searched in web and I come across different approaches: from using GAC to assembly
loading/resolving but there is also an another option possible: using for all
TaxServices the same virtual directory. E.g. virtual directory for Tenant001
could be C:\temp\Tenants\Tenant001, for all TaxServices it could be C:\temp\Services\TaxService.
Or we could go further and place all code of the same version in the only one
directory, e.g. C:\temp\Services, to build WCF Endpoints we would using ServiceHostFactory, that would construct a
service host.Is it doable? What are cons and pros? Thanks
- Edited by Boris Galiev Monday, February 20, 2012 11:15 AM grammar mistakes
All Replies
-
Monday, February 20, 2012 9:34 PM
Hello Boris,
Can you elaborate why are you trying to decouple services based on tenants?
The most common is using endpoint based on service functionality like Services\TaxService, Services\EmailService (and you do versioning for each of the service if they are used by different applications)
Regards
Jack Ernest Care About Your Craft
-
Tuesday, February 21, 2012 12:08 PM
Hello Jack,
thank you for asking me.
Historically we‘ve built a routing bus infrastructure with WCF routing services. It redirects requests based on header (TenantId) to different endpoints. This routing service sits in a DMZ and makes protocol mapping (e.g. from http to tcp) and adds tenantId to url. Adding TenantId to the target service url is critical to us, because we inject customers legacy backend systems based on this info (our customers/tenants have different legacy databases) So if we have TenantId in the url of a service, we use a custom ServiceHostFactory, that injects with Unity an appropriate legacy backend system. If a service is once constructed, it has all dependences that it needs.
Another reason to have service structure described in my first posting is the ability to monitor & manage tenant’s apps separately. It’s easy to see which apps a customer uses, if some of customers have problems due issues with theirs backbend’s databases etc., it’s possible to recycle appPools for some of them without need to reboot the complete service site.
Now we meet, of course, a challenge to build a tool that synchronizes wcf services settings( endpoints, protocols etc.) saved in our db with IIS web site structure. Theoretically it’s not an issue but who knows if this solution would work as expected
I hope I explained our problems properly…
Best regards,
Boris
- Edited by Boris Galiev Tuesday, February 21, 2012 12:12 PM
-
Wednesday, February 22, 2012 3:35 AM
Hello Boris,
If not second reason you could still have centralized services and based on header load/inject different backend(s) and cache them through the life of the service, but if you want to be able to separetely manage/recycle services GAC is your best option.
Regards
Jack
Jack Ernest Care About Your Craft
-
Wednesday, February 22, 2012 9:18 AM
Hello Jack,
we tried to read headers from ServiceHostFactory but they are not available because a wcf message is still not there at the moment when CreateServiceHost is called.
The GAC is not an option to us, we prefer to make over control of versioning ourselves and we think that our way is more transparent and it is better suited for development life cycle than a model where you have to deploy dll’s permanently to GAC while developing software on devBoxes.
Best regards,
Boris
- Edited by Boris Galiev Wednesday, February 22, 2012 9:18 AM
-
Wednesday, February 22, 2012 5:29 PM
Hello,
You can easy intercept each message (message inspector) and based on the message header you can inject valid backend which will be the same you cached in ServiceHostFactory.
I'm not sure what you mean permanently to GAC. GAC is nothing else like a folder with ability to store the same file names but with different version and with very easy automatic access by any application. You can install and uninstall any time the same like copying it to a folder and it is specially design for sharing assemblies.
The only thing if you would like to share dlls between different machines without duplicating them on each machine and you would like some central repository with dynamic loading ability- I would look in Nuget then which gain a lot of popularity recently specially in open source projects.
I mean you can try to build your very own, but it may be more like reinventing the wheel. I've seen several large distributed systems and we always were able to adjust and make our problems solvable using common practices.
Jack Ernest Care About Your Craft
- Edited by Jack Ernest Lichwa Thursday, February 23, 2012 2:33 AM I meant something completely different
- Marked As Answer by Yi-Lun LuoModerator Friday, February 24, 2012 8:02 AM
- Unmarked As Answer by Boris Galiev Friday, February 24, 2012 1:18 PM
-
Friday, February 24, 2012 1:19 PM
Thanks Jack,
I think I can follow what you say but it’s not really an answer to my question.
As long as I understand if you have requirements about running services per tenant separately
you have to build up an IIS structure like I mentioned. What I can’t grasp is
how you can properly inject something without ServiceHostFactory. I assume we both talked about stateless per call services.Best regards,
Boris
-
Friday, February 24, 2012 4:31 PM
Boris,
I'm not 100% sure what type of data you are injecting, but I thought that is rather some configuration (does not change without new deployment, app pool recycle) and it takes a while so you don't want to do it per each call. If your backends initialization is more than configuration and it is stateful (and i.e. has to work as singleton) below solution will not fit to your scenario and you will have to have separate services for each tenant...
You can still use ServiceHostFactory to initialize backends for all tenants and store it to HttpRuntime.Cache or AppFabric(Velocity). If you don't use ServiceHostFactory - first call will take longer cuz it will initialize that in the first call to service in Message Inspector....
Using Message Inspector you can intercept every message in AfterReceiveRequest:
if(HeaderMember.Equals(Tenant1))
{
Tenant.InitializeBackendForTenant1()//by getting from i.e. HttpRuntime.Cache or AppFabric and store it in
}
else if (HeaderMember.Equals(Tenant2))
{
Tenant.IntializeBackendForTenant2()//by getting from i.e. HttRuntime.Cache or AppFabric
}
Where Tenant could be static entity (only available for that call) or you can insert that to Unity Container in the same way per call.....
Like I said I'm not exactly sure how your backends are initialized,but if you used ServiceHostFactory I believe that it is stateless configuration and I'm sure that there is tons of different ways to implement it and maybe I'm missing some puzzle which will prevent you from using above solution, but I'm planning to use above pattern to initialize different security level/service throttling based on key in the header as an addition to windows credentials - to prioritize calls which coming from applications used for analysis and application used for actual trading (unfortunetelly different applications share the same services). Currently I use calls interception for compression, centralized calls tracing and centralized exception handling.
Anyway you can check possible extensibility points and maybe it will help you with making your solution more maintenable... There is a lot of sample available here
Jack Ernest Care About Your Craft
- Marked As Answer by Michael Sun [MSFT]Microsoft Employee, Moderator Thursday, March 29, 2012 3:55 AM

