In the last post i said about LinqtExtender implementing necessary property and injecting specific settings for entity objects. The issue i have is that it works fine under full / high trust settings but when running in medium trust it gives the following error:
Ouch.. it is only happening while i am using the extender from medium trust environment. As to add a little prologue, actually it creates a proxy around your original entity and if you look closely it is giving the error in .ctor(). Now lets dig in.
1: ILGenerator ilGenerator = constructorBuilder.GetILGenerator();
2:
3: ConstructorInfo baseConstructor = typeof(object).GetConstructors()[0];
4:
5: ilGenerator.Emit(OpCodes.Ldarg_0);
6: ilGenerator.Emit(OpCodes.Call, baseConstructor);
7: ilGenerator.Emit(OpCodes.Ret);
The IL code is pretty simple actually , its the method body of the proxy class constructor that calls default constructor of the base class. Now, this will work fine in full/high trust as here i require the entity class to have a default constructor. But, as i switch the mode to medium trust it will throw me the above exception. The reason why, in medium trust the framework verifies the IL generated and though it may seem from my point of view that its a valid IL as it is expecting default constructor , to framework’s context its invalid as the base object might never have any default constructor (it should throw error in high trust). In that case the call is absolutely suspicious duh…
So the valid block for this scenario would be:
1: ILGenerator ilGenerator = constructorBuilder.GetILGenerator();
2:
3: ConstructorInfo baseConstructor = null;
4: ConstructorInfo[] constructorInfos = parent.GetConstructors();
5:
6: bool containsDefaultConstructor = false;
7:
8: foreach (ConstructorInfo info in constructorInfos)
9: {
10: if (info.GetParameters().Length == 0)
11: {
12: baseConstructor = info;
13: containsDefaultConstructor = true;
14: break;
15: }
16: }
17:
18: if (!containsDefaultConstructor)
19: throw new Exception(Properties.Messages.MustHaveADefaultConstructor);
20:
21: ilGenerator.Emit(OpCodes.Ldarg_0);
22: ilGenerator.Emit(OpCodes.Call, baseConstructor);
23: ilGenerator.Emit(OpCodes.Ret);
The code is similar , just it checks for a default constructor , if not throws a valid exception and to medium trust everything looks fine. I have added a patch for extender with this as well, do check it out.
Finally, while you are doing Reflection.Emit do check this and more like, you should not emit any unmanaged code and even not play around with private stuffs , etc to avoid pitfalls.
Hope that helps
While developing LinqExtender, i have come across various scenarios that people don’t want to extent any query class or even implement any interface. Also, it is almost absurd when they have to add new extender specific attributes to their entity class. It is though not very important for people creating new provider with small codebase but with large codebase it soon becomes a pain to modify each class.
The solution is to make Extender as a container , which is people will write their logic to act on their specific entity or list of entities, also define their settings via fluent interface. To wrap it around , there is a basic ORM that comes with the extender pack and i have a made LibraryContext on top of SqlQueryContext<T>. Inside, the constructor i wrote the following code to define the extender specific settings.
1: Extender
2: .Settings
3: .For<Base>()
4: .Begin
5: .Property(x => x.Id).MarkAsUnique
6: .End
7: .For<Book>()
8: .MapToEntity("book") 9: .Begin
10: .Property(x => x.Id).MapToAttribute("Bk_Id") 11: .Property(x => x.ShelveId).MapToAttribute("Shelve_Id") 12: .Property(x => x.Title).MapToAttribute("Bk_Title") 13: .Property(x => x.BookInfo).MarkToIgnore()
14: .End
15: .For<Library>()
16: .MapToEntity("Bk_Library") 17: .InstantiateIn(this);
Note that there is a base settings that will be applied to all the common properties under my project and is a local class inherited from LinqExtender.Configruation.All. During the instantiation it will be applied to the current container instance.
Now, as i have said extender should be used a container so that there should be no strings attached. In my entity class, i can implement IQueryObject to mark it as a query class, but if not then extender should be smarter enough to implement it internally when the entity is used in LINQ query via extender query class. Actually , under the hood it dynamically creates a proxy via Reflection.Emit that has the settings and ensures IQueryObject. I will in days time come out with a open source project where i have practiced all these reflection stuffs and which i will extensively blog about , so stay tuned.
To make it more clear i have re-implemented the LINQ to Twitter post using the new extender. So few things like implementing IQueryObject and defining unique identifier is no longer required. You can get the new copy at the end of the post. Also, before i forget, there is a tiny catch which is you can’t left the extender auto generate settings, if you are using it in medium-trust as Reflection.Emit does not work in such environment. In that case you will have to implement IQueryObject by hand and add the attributes manually to make it work so i am leaving LinqToTwitter post untouched [See bottom]. I know most of the good hosting providers these days support high trust and soon i think medium trust will become classic with dynamic proxy generation and cross domain request is becoming growing common (Just my two cents, don't want to get in war with these ;)).
In previous release you can access the Fluent implementation of Bucket just by Bucket.Instance, as it seems that i have somewhere statically stored the bucket object and the syntax bit more sexy but considering multiple threads , there is a possibility of data corruption. Therefore Bucket instance is passed to Query<T> overrides as IBucket and new syntax for Bucket.Instance follows
1: FluentBucket fluentBucket = FluentBucket.As(bucket);
2: // do your work.
Down to acknowledgement , Microsoft Germany has published two new tutorials around LinqExtender using LinqToFlickr and LinqToTwitter that also led me fix the VB method call issue and thanks Lars and Tim. In German way i would say, “Danke[Dang – ko]”. You can find the recordings in the following URLs
http://www.microsoft.com/germany/msdn/solve/codeclips/library.aspx?id=msdn_de_33389
http://www.microsoft.com/germany/msdn/solve/codeclips/library.aspx?id=msdn_de_33369
Finally, while we are preparing our new Sitefinity release and making some LINQ extensions, bob’s comments were helpful shaping the release as well and nonetheless all community reviews and feedbacks are great. Try the new release here.
Enjoy !!!
June 7, 2009 => Correction ,Reflecton.Emit does not work in medium trust for unmanaged IL codes and possible IL that might destabilize the runtime that it finds by verifying the assembly, will show more on it in upcoming post. Added a patch of extender, this will work in medium trust with auto implementaion and fluent configuration.