首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >序列化某些类型集合时针对Azure WebRole的WCF超时

序列化某些类型集合时针对Azure WebRole的WCF超时
EN

Stack Overflow用户
提问于 2013-06-04 17:56:36
回答 1查看 190关注 0票数 0

我有一个托管在Azure角色上的无状态后端服务,它可以查询实体框架容器等。客户端使用、WCF、wsHttpBinding与其进行通信。客户端在调用特定方法时会从后端接收超时,即使在某些情况下我已经解决了这个问题,但我似乎无法确定根本原因。

到目前为止,我知道的是:

  • 失败的方法似乎是返回某些类型集合的方法。这包括IEnumerable<T>和从LINQ查询获得的结果,以及MembershipUserCollection
  • 在某些情况下,解决方法是将.ToList()添加到要返回的集合中。
  • 当后端托管在Azure中时,这些方法只会使失败
  • Azure负载平衡器似乎不是原因,而是症状:每次方法超时时,日志显示它实际上早在1分钟限制之前就退出了。

以下是其中一个失败的方法:

WCF接口

代码语言:javascript
复制
    [OperationContract(Action = "http://tempuri.org/IBackendService/GetAllUsers", ReplyAction = "http://tempuri.org/IBackendService/GetAllUsersResponse")]
    MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords);

WCF实现(简化):

代码语言:javascript
复制
    protected UserRepository Users;

    public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
    {
        // Get all users in the page range specified.
        var userEntities = Users.GetAll();
        var users = new MembershipUserCollection();
        userEntities = userEntities.GetPagedRange(pageIndex, pageSize).ToList();
        userEntities.ForEach(ue => users.Add(Mappings.Map<UserEntity, User>(ue)));
        totalRecords = userEntities.Count();
        return users;
    }

映射是一个类,它使用AutoMapper定义数据和业务对象之间的映射规则。User继承自MembershipUser。下面是与此相关的内容:(WIP )。请原谅这乱七八糟。

代码语言:javascript
复制
        Mapper.CreateMap<UserEntity, User>()
            .ConstructUsing(ue => new User
                (
                ue.UserId,
                ue.ProviderName,
                ue.UserName,
                ue.Email,
                ue.PasswordQuestion,
                ue.IsApproved,
                ue.IsLockedOut,
                ue.CreationDate,
                ue.LastLoginDate.HasValue ? ue.LastLoginDate.Value : DateTime.MinValue,
                ue.LastActivityDate.HasValue ? ue.LastActivityDate.Value : DateTime.MinValue,
                ue.LastPasswordChangedDate.HasValue ? ue.LastPasswordChangedDate.Value : DateTime.MinValue,
                ue.LastLockoutDate.HasValue ? ue.LastLockoutDate.Value : DateTime.MinValue,
                ue.Comment,
                ue.Customers.Select(Map<CustomerEntity, Customer>).ToList(),
                ue.Roles.Select(Map<RoleEntity, Role>).ToList(),
                ue.Roles.SelectMany(r => r.Activities).Select(Map<ActivityEntity, Activity>).ToList()
                ))
            .IgnoreAllNonExisting();

        Mapper.CreateMap<User, UserEntity>()
            .ForMember(ue => ue.Comment, opt => opt.MapFrom(u => u.Comment))
            .ForMember(ue => ue.CreationDate, opt => opt.MapFrom(u => u.CreationDate))
            .ForMember(ue => ue.Email, opt => opt.MapFrom(u => u.Email))
            .ForMember(ue => ue.IsApproved, opt => opt.MapFrom(u => u.IsApproved))
            .ForMember(ue => ue.IsLockedOut, opt => opt.MapFrom(u => u.IsLockedOut))
            .ForMember(ue => ue.LastActivityDate, opt => opt.MapFrom(u => u.LastActivityDate.Equals(DateTime.MinValue) ? (DateTime?)null : u.LastActivityDate))
            .ForMember(ue => ue.LastLockoutDate, opt => opt.MapFrom(u => u.LastLockoutDate.Equals(DateTime.MinValue) ? (DateTime?)null : u.LastLockoutDate))
            .ForMember(ue => ue.LastLoginDate, opt => opt.MapFrom(u => u.LastLoginDate.Equals(DateTime.MinValue) ? (DateTime?)null : u.LastLoginDate))
            .ForMember(ue => ue.LastPasswordChangedDate,
                opt => opt.MapFrom(u => u.LastPasswordChangedDate.Equals(DateTime.MinValue) ? (DateTime?)null : u.LastPasswordChangedDate))
            .ForMember(ue => ue.PasswordQuestion, opt => opt.MapFrom(u => u.PasswordQuestion))
            .ForMember(ue => ue.ProviderName, opt => opt.MapFrom(u => u.ProviderName))
            .ForMember(ue => ue.UserId, opt => opt.MapFrom(u => (int)u.ProviderUserKey))
            .ForMember(ue => ue.UserName, opt => opt.MapFrom(u => u.UserName))
            .ForMember(ue => ue.Password, opt => opt.Ignore())
            .ForMember(ue => ue.PasswordAnswer, opt => opt.Ignore())
            .ForMember(ue => ue.ApplicationName, opt => opt.Ignore())
            .ForMember(ue => ue.Roles, opt => opt.Ignore())
            .ForMember(ue => ue.Customers, opt => opt.Ignore())
            .IgnoreAllNonExisting();

IgnoreAllNonExisting是一种扩展方法:

代码语言:javascript
复制
    public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
    {
        var sourceType = typeof(TSource);
        var destinationType = typeof(TDestination);
        var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType == sourceType && x.DestinationType == destinationType);
        foreach (var property in existingMaps.GetUnmappedPropertyNames())
        {
            expression.ForMember(property, opt => opt.Ignore());
        }

        return expression;
    }

我最好的猜测是,这是WCF层中的序列化问题,但我不知道是什么触发了它。除此之外,我完全一无所知。

我还应该查些什么?你还需要更多信息吗?

编辑:为澄清添加了moar片段.

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-11 19:46:16

看来我终于找到答案了。

MembershipUser似乎一点也不能序列化,尽管它被标记为Serializable属性。根据this,它也被标记为SecurityPermission属性,这禁止出于安全原因的序列化。

用自相矛盾的属性标记类有什么意义,我猜我永远也不会知道。

更奇怪的是,只有在Azure WebRole上承载WCF服务时才会出现超时问题。如果你把它放在其他地方,它会抛出一个CommunicationException,这是有道理的。我想那边的Azure肯定有某种虫子。

无论如何,通过使 User 类不继承 MembershipUser来解决这个问题,将 MembershipUserCollection E 116替换为E 217 IEnumerable<User>

希望这能帮到别人。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16924416

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档