Azure缓存和实体框架反序列化问题

5
我在Azure上部署了一个使用共同缓存的Web项目。我有两个这个Web角色的实例。
我使用Entity Framework 5,从数据库查找某些实体后,将它们缓存在共同缓存中。
我的实体定义在名为Drt.BusinessLayer.Entities的类库中。
然而,当我访问我的Web应用程序时,出现以下错误:
反序列化器无法加载要反序列化的类型,因为在程序集“EntityFrameworkDynamicProxies-Drt.BusinessLayer.Entities,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”中找不到类型“System.Data.Entity.DynamicProxies.Country_4C17F5A60A033813EC420C752F1026C02FA5FC07D491A3190ED09E0B7509DD85”。请检查被序列化的类型和被反序列化的类型具有相同的契约,并且使用相同的程序集。
有时也会出现以下错误:
找不到程序集“EntityFrameworkDynamicProxies-Drt.BusinessLayer.Entities,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”。
似乎获取实体对象/反序列化时出现了错误。由于它们是Web角色的2个实例,Instance1可能会将某些实体对象放入缓存中,Instance2可能会将其取出。我原以为这会起作用,但我不确定为什么会出现此错误....
有人能帮忙/提供建议吗?
2个回答

4
我遇到了同样的问题。至少在我的情况下,问题出在EF包装所有模型类的DynamicProxies上。换句话说,你可能会认为自己正在检索一个叫做Country的类,但实际上,在幕后,EF实际上是动态生成了一个叫做Country_4C17F5A60A033813EC420C752F1026C02FA5FC07D491A3190ED09E0B7509DD85之类的类。名称的最后一部分显然是在运行时生成的,并且可以期望在应用程序生命周期内保持不变 - 但是(这是关键),仅在同一应用程序域的同一实例中是如此。如果你有两台机器访问相同的进程外缓存,则其中一台将存储类型为Country_4C17F5A60A033813EC420C752F1026C02FA5FC07D491A3190ED09E0B7509DD85的对象,但该类型在另一台机器上根本不存在。的动态Country类将是像Country_JF7ASDF8ASDF8ADSF88989ASDF8778802348JKOJASDLKJQAWPEORIU7879243AS这样的东西,因此在它反序列化序列化对象时就不会有任何类型。如果重新启动Web应用程序运行的应用程序域,也会发生同样的事情。
我相信微软的大脑可以想出更好的解决方案,但我使用的解决方案是在缓存EF对象之前进行“浅克隆”。我使用的C#方法如下:
public static class TypeHelper
{
    public static T ShallowClone<T>(this T obj) where T : class
    {
        if (obj == null) return null;
        var newObj = Activator.CreateInstance<T>();
        var fields = typeof(T).GetFields();
        foreach (var field in fields)
        {
            if (field.IsPublic && (field.FieldType.IsValueType || field.FieldType == typeof(string)))
            {
                field.SetValue(newObj, field.GetValue(obj));
            }
        }
        var properties = typeof(T).GetProperties();
        foreach (var property in properties)
        {
            if ((property.CanRead && property.CanWrite) && 
                (property.PropertyType.IsValueType || property.PropertyType == typeof(string)))
            {
                property.SetValue(newObj, property.GetValue(obj, null), null);
            }
        }
        return newObj;
    }
}

这样做可以同时解决两个问题:(1)确保只缓存我特别关心的EF对象,而不是它所依附的整个对象图(有时可能很大);(2)缓存的对象是一种通用类型,而不是动态生成的类型:Country而不是 Country_4C17F5A60A033813EC420C752F1026C02FA5FC07D491A3190ED09E0B7509DD85
当然,这并不完美,但在许多情况下似乎是一个合理的解决方法。
如果微软公司的好人能够想出一种不需要这样做的EF对象缓存方式那就太好了。

0

我对特定的Azure缓存不熟悉,但我猜想在将实体传递给进行序列化的任何东西之前,您需要完全填充它们,这是分布式或进程外缓存会做的事情。

因此,在获取实体时,只需对所有关系执行.Include()或禁用延迟初始化即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接