Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Update to view dictionary adapter
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  5 messages - Collapse all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Lee Henson  
View profile  
 More options Mar 22 2007, 9:09 am
From: "Lee Henson" <lee.m.hen...@gmail.com>
Date: Thu, 22 Mar 2007 06:09:49 -0700
Local: Thurs, Mar 22 2007 9:09 am
Subject: Update to view dictionary adapter
I've added a couple of extra features to that reflecting view
dictionary adapter I stole from the eleutian guys. I'm also using it
to now strongly-type my Session usage, as well as Flash and
PropertyBag. To stop key collisions, I've got a custom attribute on
the dictionary adapter interface which allows me to specify a prefix
to the generated dictionary key. For example:

[DictionaryAdapterKeyPrefix("Artist.Registration.")]
public interface IArtistRegistrationSessionAdapter :
IDictionaryAdapter
{
        AccountRegistration AccountRegistration { get; set; }
        ContactDetails ContactDetails { get; set; }
        Nullable<PackageType> PackageType { get; set; }
        string RegisteredUserName { get; set; }

}

You can also do session adapter interface inheritance, with the key
prefix defaulting to the most specific definition it can find. If I
recall correctly, there were a few bugs in the old code which are
fixed here.

If people find this useful perhaps it might be worth adding to the
code generator contrib project?

=============================

public interface IDictionaryAdapter
{

}

public interface IDictionaryAdapterFactory
{
        T GetAdapter<T>(IDictionary session) where T : IDictionaryAdapter;

}

[AttributeUsage(AttributeTargets.Interface, AllowMultiple = false,
Inherited = true)]
public class DictionaryAdapterKeyPrefixAttribute : Attribute
{
        private string keyPrefix;

        public DictionaryAdapterKeyPrefixAttribute()
        {
        }

        public DictionaryAdapterKeyPrefixAttribute(string keyPrefix)
        {
                this.keyPrefix = keyPrefix;
        }

        public string KeyPrefix
        {
                get { return keyPrefix; }
                set { keyPrefix = value; }
        }

}

public class DictionaryAdapterFactory : IDictionaryAdapterFactory
{
        public T GetAdapter<T>(IDictionary dictionary) where T :
IDictionaryAdapter
        {
                AppDomain appDomain = Thread.GetDomain();
                string adapterAssemblyName = GetAdapterAssemblyName<T>();
                Assembly adapterAssembly = GetExistingAdapterAssembly(appDomain,
adapterAssemblyName);

                if (adapterAssembly == null)
                        adapterAssembly = CreateAdapterAssembly<T>(appDomain,
adapterAssemblyName);

                return GetExistingAdapter<T>(adapterAssembly, dictionary);
        }

        private static Assembly CreateAdapterAssembly<T>(AppDomain appDomain,
string adapterAssemblyName)
        {
                AssemblyName assemblyName = new AssemblyName(adapterAssemblyName);
                AssemblyBuilder assemblyBuilder =
appDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.Run);
                ModuleBuilder moduleBuilder =
assemblyBuilder.DefineDynamicModule(adapterAssemblyName);

                TypeBuilder typeBuilder = CreateAdapterType<T>(moduleBuilder);
                FieldBuilder dictionaryField =
CreateAdapterDictionaryField(typeBuilder);
                CreateAdapterConstructor(typeBuilder, dictionaryField);

                List<PropertyInfo> properties = new List<PropertyInfo>();
                RecursivelyDiscoverProperties(properties, typeof(T));
                properties.ForEach(delegate(PropertyInfo propertyInfo)
{ CreateAdapterProperty(typeBuilder, dictionaryField,
propertyInfo); });

                typeBuilder.CreateType();

                return assemblyBuilder;
        }

        private static void CreateAdapterConstructor(TypeBuilder typeBuilder,
FieldBuilder dictionaryField)
        {
                ConstructorBuilder constructorBuilder =
typeBuilder.DefineConstructor(
                        MethodAttributes.Public | MethodAttributes.HideBySig,
CallingConventions.Standard, new Type[] { typeof(IDictionary) });
                constructorBuilder.DefineParameter(1, ParameterAttributes.None,
"dictionary");

                ILGenerator ilGenerator = constructorBuilder.GetILGenerator();

                Type objType = Type.GetType("System.Object");
                ConstructorInfo objectConstructorInfo = objType.GetConstructor(new
Type[0]);

                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Call, objectConstructorInfo);
                ilGenerator.Emit(OpCodes.Nop);
                ilGenerator.Emit(OpCodes.Nop);
                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Ldarg_1);
                ilGenerator.Emit(OpCodes.Stfld, dictionaryField);
                ilGenerator.Emit(OpCodes.Nop);
                ilGenerator.Emit(OpCodes.Ret);
        }

        private static FieldBuilder CreateAdapterDictionaryField(TypeBuilder
typeBuilder)
        {
                return typeBuilder.DefineField("dictionary", typeof(IDictionary),
FieldAttributes.Private);
        }

        private static void CreateAdapterProperty(TypeBuilder typeBuilder,
FieldBuilder dictionaryField, PropertyInfo property)
        {
                PropertyBuilder propertyBuilder =
typeBuilder.DefineProperty(property.Name, property.Attributes,
property.PropertyType, null);
                MethodAttributes propertyMethodAttributes = MethodAttributes.Public
| MethodAttributes.SpecialName | MethodAttributes.HideBySig |
MethodAttributes.Virtual;

                if (property.CanRead)
                        CreateAdapterPropertyGetMethod(typeBuilder, dictionaryField,
propertyBuilder, property, propertyMethodAttributes);

                if (property.CanWrite)
                        CreateAdapterPropertySetMethod(typeBuilder, dictionaryField,
propertyBuilder, property, propertyMethodAttributes);
        }

        private static void CreateAdapterPropertyGetMethod(TypeBuilder
typeBuilder, FieldBuilder dictionaryField, PropertyBuilder
propertyBuilder, PropertyInfo property, MethodAttributes
propertyMethodAttributes)
        {
                MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" +
property.Name, propertyMethodAttributes, property.PropertyType, null);

                ILGenerator getILGenerator = getMethodBuilder.GetILGenerator();
                Label label = getILGenerator.DefineLabel();

                getILGenerator.DeclareLocal(property.PropertyType);
                getILGenerator.Emit(OpCodes.Nop);
                getILGenerator.Emit(OpCodes.Ldarg_0);
                getILGenerator.Emit(OpCodes.Ldfld, dictionaryField);
                getILGenerator.Emit(OpCodes.Ldstr,
GetDictionaryFieldName(property));
                getILGenerator.Emit(OpCodes.Callvirt,
typeof(IDictionary).GetMethod("get_Item", new Type[]
{ typeof(Object) }));

                if (property.PropertyType.IsValueType)
                        getILGenerator.Emit(OpCodes.Unbox_Any, property.PropertyType);
                else
                        getILGenerator.Emit(OpCodes.Castclass, property.PropertyType);

                getILGenerator.Emit(OpCodes.Stloc_0);
                getILGenerator.Emit(OpCodes.Br_S, label);
                getILGenerator.MarkLabel(label);
                getILGenerator.Emit(OpCodes.Ldloc_0);
                getILGenerator.Emit(OpCodes.Ret);

                propertyBuilder.SetGetMethod(getMethodBuilder);
        }

        private static void CreateAdapterPropertySetMethod(TypeBuilder
typeBuilder, FieldBuilder dictionaryField, PropertyBuilder
propertyBuilder, PropertyInfo property, MethodAttributes
propertyMethodAttributes)
        {
                MethodBuilder setMethodBuilder = typeBuilder.DefineMethod(
                        "set_" + property.Name, propertyMethodAttributes, null, new Type[]
{ property.PropertyType });

                ILGenerator setILGenerator = setMethodBuilder.GetILGenerator();

                setILGenerator.Emit(OpCodes.Nop);
                setILGenerator.Emit(OpCodes.Ldarg_0);
                setILGenerator.Emit(OpCodes.Ldfld, dictionaryField);
                setILGenerator.Emit(OpCodes.Ldstr,
GetDictionaryFieldName(property));
                setILGenerator.Emit(OpCodes.Ldarg_1);

                if (property.PropertyType.IsValueType)
                        setILGenerator.Emit(OpCodes.Box, property.PropertyType);

                setILGenerator.Emit(OpCodes.Callvirt,
typeof(IDictionary).GetMethod("set_Item", new Type[] { typeof(Object),
typeof(Object) }));
                setILGenerator.Emit(OpCodes.Nop);
                setILGenerator.Emit(OpCodes.Ret);

                propertyBuilder.SetSetMethod(setMethodBuilder);
        }

        private static TypeBuilder CreateAdapterType<T>(ModuleBuilder
moduleBuilder)
        {
                TypeBuilder typeBuilder =
moduleBuilder.DefineType(GetAdapterFullTypeName<T>(),
TypeAttributes.Public | TypeAttributes.Class |
TypeAttributes.BeforeFieldInit);
                typeBuilder.AddInterfaceImplementation(typeof(T));

                return typeBuilder;
        }

        private static string GetAdapterAssemblyName<T>()
        {
                return typeof(T).Assembly.GetName().Name + "." + typeof(T).FullName
+ ".DictionaryAdapter";
        }

        private static string GetAdapterFullTypeName<T>()
        {
                return typeof(T).Namespace + "." + GetAdapterTypeName<T>();
        }

        private static string GetAdapterTypeName<T>()
        {
                return typeof(T).Name.Substring(1) + "DictionaryAdapter";
        }

        private static DictionaryAdapterKeyPrefixAttribute
GetDictionaryAdapterAttribute(PropertyInfo property)
        {
                List<Type> interfaces = new List<Type>();

                interfaces.Add(property.DeclaringType);
                interfaces.AddRange(property.DeclaringType.GetInterfaces());

                foreach (Type type in interfaces)
                {
                        object[] attributes =
type.GetCustomAttributes(typeof(DictionaryAdapterKeyPrefixAttribute),
false);

                        if (attributes.Length > 0)
                                return (DictionaryAdapterKeyPrefixAttribute) attributes[0];
                }

                return null;
        }

        private static string GetDictionaryFieldName(PropertyInfo property)
        {
                DictionaryAdapterKeyPrefixAttribute
dictionaryAdapterKeyPrefixAttribute =
GetDictionaryAdapterAttribute(property);

                string prefix = dictionaryAdapterKeyPrefixAttribute == null
                                                        ? string.Empty
                                                        : dictionaryAdapterKeyPrefixAttribute.KeyPrefix;

                return prefix + property.Name;
        }

        private static T GetExistingAdapter<T>(Assembly assembly, IDictionary
dictionary)
        {
                string adapterFullTypeName = GetAdapterFullTypeName<T>();
                return
(T)Activator.CreateInstance(assembly.GetType(adapterFullTypeName,
true), dictionary);
        }

        private static Assembly GetExistingAdapterAssembly(AppDomain
appDomain, string assemblyName)
        {
                return Array.Find(appDomain.GetAssemblies(),
                        delegate(Assembly assembly) { return assembly.GetName().Name ==
assemblyName; });
        }

        private static void RecursivelyDiscoverProperties(List<PropertyInfo>
properties, Type currentType)
        {
                properties.AddRange(currentType.GetProperties(BindingFlags.Public |
BindingFlags.Instance));

                Array.ForEach(currentType.GetInterfaces(),
                        delegate(Type parentInterface)
{ RecursivelyDiscoverProperties(properties, parentInterface); });
        }


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jacob Lewallen  
View profile  
 More options Mar 22 2007, 12:53 pm
From: "Jacob Lewallen" <jlewa...@gmail.com>
Date: Thu, 22 Mar 2007 08:53:45 -0800
Local: Thurs, Mar 22 2007 12:53 pm
Subject: Re: Update to view dictionary adapter
I like it Lee. I'll commit that as soon as I get a chance. I was
planning a blog post soon about some other stuff you can do, I'll have
to toss it up before it becomes outdated... heheh. Nothing like the
attribute though, again, great stuff.

jacob

On 3/22/07, Lee Henson <lee.m.hen...@gmail.com> wrote:

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Lee Henson  
View profile  
 More options Mar 22 2007, 1:16 pm
From: "Lee Henson" <lee.m.hen...@gmail.com>
Date: Thu, 22 Mar 2007 10:16:12 -0700
Local: Thurs, Mar 22 2007 1:16 pm
Subject: Re: Update to view dictionary adapter

> I was planning a blog post soon about some other stuff you can do

Great! I look forward to your posts with equal parts excitement
(because you guys are always coming up with interesting ideas) and
dread (because then I decide I *HAVE TO* implement them immendiately
on my project).

>:]

On Mar 22, 4:53 pm, "Jacob Lewallen" <jlewa...@gmail.com> wrote:

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
jacob  
View profile  
 More options Mar 22 2007, 1:26 pm
From: "jacob" <jlewa...@gmail.com>
Date: Thu, 22 Mar 2007 17:26:07 -0000
Local: Thurs, Mar 22 2007 1:26 pm
Subject: Re: Update to view dictionary adapter
Haha, well there I tossed it up. I had written in yesterday and wasn't
sure if I was done... so yeah I guess I am. It's nothing new code-
wise, just suggestions on other ways to use it. I've definitely
learned my lesson, code+ideas... not just ideas. Hehe.

jacob

On Mar 22, 10:16 am, "Lee Henson" <lee.m.hen...@gmail.com> wrote:

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jacob Lewallen  
View profile  
 More options Mar 22 2007, 1:41 pm
From: "Jacob Lewallen" <jlewa...@gmail.com>
Date: Thu, 22 Mar 2007 10:41:07 -0700
Local: Thurs, Mar 22 2007 1:41 pm
Subject: Re: Update to view dictionary adapter
I checked that code in Lee.

jacob

On 3/22/07, Lee Henson <lee.m.hen...@gmail.com> wrote:

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »