giovedì 21 giugno 2012 18:02
I'm looking for a best practice to use when designing an application that allows 3rd party components to store data using code-first EF (that is, via a custom DbContext).
As my app can host 3rd party plugins, I hold them in sandbox appdomains with certain trust restrictions. Obviously, allowing these plugins full access to my app's DB would be a mistake.
And so, given that I also would like these components to be able to upgrade their code-first contexts via code-first independently of other components, I initially looked at using independent data contexts for each component - including my own components that I develop using the same framework complying to the same sandbox.
I'd like sandboxed components to be granted read-only access to other component contexts (if that component gives permissions). And the ability for component to upgrade/downgrade its own contexts thus also fits into the multi context model.
Is this the standard, best-practice for this design scenario? What is the best way to enforce permissions, protecting component contexts from other components unless permissions are explicitly granted?
I have looked at the other posts. These focus on using multiple contexts in nested situations, but not so much on this particular scenario.
Tutte le risposte
giovedì 21 giugno 2012 23:10
I would hesitate to expose EF objects or contexts to 3rd-party components at all. For compatibility reasons. If you make a change to your database design, and your objects change, wouldn't that break the plug-ins? Same thing with having those 3rd-party sandboxed components give access to each other's contexts. If a 3rd-party component modifies their object, it could break another component. Perhaps that is not an issue here, but since you are loading them into AppDomains that indicates you have a level of concern about such things.
For accessing "central" objects I suggest creating a separate interface that completely decouples the sandboxed components from your EF objects and contexts. Same thing for different sandboxed components talking to each other. But maybe this depends on your situation.
This is certainly more work though.
venerdì 22 giugno 2012 08:09
Thanks for your input. Yes, if a third party component uses entities from another component, and that component then ships a new version with amended entities, then in theory, that component would break.
However I've been thinking through the scenarios that would actually break the mould. If, say, a component adds a new property to an entity class, and ships with that new property (plus amended database to store this new property), then I assume if another component references the new assembly, it would just get the newly amended class with the extra property. Having not been aware of it previously, the component would just not use this new property and it would continue to work, correct?
However, if there was a large change, e.g. an entity removed or renamed, then the component that still thinks it is using the old entity class would then be unable to load the type from the new assembly. Which _would_ break compatibility.
So, there are some changes which are backwards compatible, and some that are not, correct?
So are there two approaches (if anyone has any input on this I'd be grateful as this is a fundamental point - perhaps someone from MS looking at this forum could make some suggestions for others to follow?):
(i) Maintain backwards compatibility in the way you change your entities over time - i.e. do not rename or remove old properties. This seems a bit restrictive, or:
(ii) Only expose shared data to other components by means of standard .NET types and an interop interface. To maintain backwards compatibility, do not make a breaking change to this interface but only add interface methods over time.
Which approach is best, or is there another approach to this problem?
sabato 23 giugno 2012 08:36
For information, I've decided that a component should only expose data (or functionality) to other components via a known external interface placed in an interface DLL that is shared by the components sharing access to each other, and that a component should never share its context with others, even if only in a read-only sense.
It's the responsibility of the component developer to ensure that any changes to this external interface retain backwards compatibility.
This interface may expose members that are code-first entities, but these will be placed in the common interface DLL and will thus follow the same requirements for retaining backwards compatibility for developers who have not yet upgraded.
I'm taking it that sounds sensible - if anyone else has any further suggestions, I'd be grateful you let me know.
sabato 23 giugno 2012 11:00
I've tried to stay away from it due the complexity of pipelines, but actually a lot of the plumbing work is done by Managed Add-In Framework (MAF) and this allows suitable sandboxing using appdomains for you.
- Contrassegnato come risposta Markos101 sabato 23 giugno 2012 11:00