0

とりわけ、 Entity FrameworkコンテナーをクエリするAzure Web ロールでホストされているステートレス バックエンド サービスがあります。クライアントは、WCFおよび. クライアントは、特定のメソッドを呼び出すときにバックエンドからタイムアウトを受け取ります。場合によってはこれを回避しましたが、根本的な原因を特定できないようです。wsHttpBinding

これが私がこれまでに知っていることです:

  • 失敗したメソッドは、特定のタイプのコレクションを返すメソッドのようです。これにはIEnumerable<T>、LINQ クエリから取得した結果が含まれますMembershipUserCollection
  • 場合によっては、.ToList()返されるコレクションに追加することで回避できました。
  • これらのメソッドは、バックエンドが Azure でホストされている場合にのみ失敗します。
  • Azure ロード バランサーが原因ではないようですが、症状として、メソッドがタイムアウトするたびに、1 分間の制限よりもかなり前にメソッドが実際に終了したことがログに示されます。

失敗するメソッドの 1 つを次に示します。

WCF インターフェイス:

    [OperationContract(Action = "http://tempuri.org/IBackendService/GetAllUsers", ReplyAction = "http://tempuri.org/IBackendService/GetAllUsersResponse")]
    MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords);

WCF 実装(簡略化):

    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;
    }

Mappingsは、AutoMapper を使用してデータとビジネス オブジェクト間のマッピング ルールを定義するクラスです。Userから継承しMembershipUserます。関連するものは次のとおりです:(WIP。混乱を許してください。)

        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は拡張メソッドです。

    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 スニペットを追加しました。

4

1 に答える 1

1

やっと答えを見つけたようです。

属性でマークされていても、MembershipUserクラスはまったくシリアル化できないようです。thisSerializableによると、セキュリティ上の理由からシリアル化を禁止する属性もマークされています。SecurityPermission

矛盾する属性を持つクラスをマークすることにどのような意味があるのか​​、私にはわからないでしょう。

さらに奇妙なのは、Azure WebRole で WCF サービスをホストしている場合にのみタイムアウトの問題が発生することです。他の場所でホストすると、意味のある がスローされますCommunicationException。あそこの Azure になんらかのバグがあるに違いないと思います。

とにかく、クラスを から継承しないようにすることでこれを解決し、 の出現箇所をに置き換えましUser MembershipUser MembershipUserCollection IEnumerable<User>

これが他の誰かに役立つことを願っています。

于 2013-06-11T19:46:16.973 に答える