Использование лучших практик для цепной ответственности в ASP. NET Core - PullRequest
0 голосов
/ 22 апреля 2020

У меня есть сценарий для входа пользователя. Я пишу этот код для проверки пользователя, если подтвердите возвращение успешного сообщения.

Я использую шаблон ответственности цепочки для этой проверки, но это кажется уродливым, потому что мне нужно больше new в этом классе.

Теперь я хочу написать чистую и лучшую практику использования этого шаблона.

Как я могу это сделать?

public abstract class ValidateUser
{
    protected readonly ValidateUser _validateUser;

    public ValidateUser(ValidateUser validateUser)
    {
        _validateUser = validateUser;
    }

    public abstract UserContext ValidateUserLogin(UserContext request);
}

CheckIsActive:

public class CheckIsActive : ValidateUser
{
    public CheckIsActive(ValidateUser validateUser) : base(validateUser)
    {
    }

    public override UserContext ValidateUserLogin(UserContext request)
    {
        if (request.Context.IsActive)
        {
            return _validateUser.ValidateUserLogin(request);
        }

        return new UserContext
        {
            Message = "User Not Active"
        };
    }
}

CheckPhoneConfirmed:

public class CheckPhoneConfirmed : ValidateUser
{
    public CheckPhoneConfirmed(ValidateUser validateUser) : base(validateUser)
    {
    }

    public override UserContext ValidateUserLogin(UserContext request)
    {
        if (request.Context.ConfirmPhoneNumber)
        {
            return _validateUser.ValidateUserLogin(request);
        }

        return new UserContext
        {
            Message="Phone Number Not confirmed"
        };
    }
}

CheckIsLockedAccount:

public  class CheckIsLockedAccount : ValidateUser
{
    public CheckIsLockedAccount(ValidateUser validateUser) : base(validateUser)
    {
    }

    public override UserContext ValidateUserLogin(UserContext request)
    {
        if (!request.Context.IsLockedEnd)
        {
            return new UserContext
            {
                Context = request.Context
            };
        }

        return new UserContext
        {
            Message = $"Your account is deactivated from to date {request.Context.LockedEnd}"
        };
    }
}

, и я использую это Validate следующим образом:

var validate = new CheckIsActive(new CheckPhoneConfirmed(new CheckIsLockedAccount(null)));
var validateUserContext = validate.ValidateUserLogin(new UserContext
                {
                    Context = findUSer.Result,
                    Message = null
                });

Ответы [ 2 ]

0 голосов
/ 22 апреля 2020

Вы можете использовать. net основной конвейер промежуточного программного обеспечения, основанный только на шаблоне цепочки ответственности.

app.Use(async (context, next) =>
{
    if (context.Request.HttpContext.User.HasClaim("IsLockedEnd", "true"))
    {
        await next();
    }                
});
app.Use(async (context, next) =>
{
    if (context.Request.HttpContext.User.HasClaim("ConfirmPhoneNumber", "true"))
    {
        await next();
    }
});
app.Use(async (context, next) =>
{
    if (context.Request.HttpContext.User.HasClaim("IsActive", "true"))
    {
        await next();
    }
});
0 голосов
/ 22 апреля 2020

Я не чувствую, что этот шаблон подходит для проверки.

Если вы Google, вы найдете следующее описание вашего шаблона:

Цепочка ответственности - это шаблон поведенческого дизайна, который позволяет передавать запрашивать по цепочке потенциальных обработчиков, пока один из них не обработает запрос. Шаблон позволяет нескольким объектам обрабатывать запрос без привязки класса отправителя к конкретным классам получателей.

. Я не думаю, что это имеет место в вашем решении. Так как я чувствую, что вы не хотите обрабатывать разные проверки в разных местах ?? Я думаю, что вы используете этот шаблон как шаблон декоратора.

Вместо этого попробуйте следующее:

Как насчет того, чтобы разделить ваши объекты на следующие:

Сначала вам нужен абстрактный класс так что вы можете позже определить ваше правило валидации

 public abstract class ValidationRule
    {
        public string Property { get; set; }
        public string Error { get; set; }

        public ValidationRule(string property)
        {
            Property = property;
            Error = property + " is not valid";
        }

        public ValidationRule(string property, string error)
            : this(property)
        {
            Error = error;
        }

        // validation method. To be implemented in derived classes

        public abstract bool Validate(Validator validator);

        // gets value for given business object's property using reflection

        protected object GetPropertyValue(Validator validator)
        {
            // note: reflection is relatively slow
            return validator.GetType().GetProperty(Property).GetValue(validator, null);
        }
    }

Затем вы можете сделать этот класс более конкретным валидатором. Может быть, законченное правило или что-то еще, что вы можете использовать повторно, например:

public class ValidateRegex : ValidationRule
    {
        protected string Pattern { get; set; }

        public ValidateRegex(string propertyName, string pattern)
            : base(propertyName)
        {
            Pattern = pattern;
        }

        public ValidateRegex(string propertyName, string errorMessage, string pattern)
            : this(propertyName, pattern)
        {
            Error = errorMessage;
        }

        public override bool Validate(Validator validator)
        {
            return Regex.Match(GetPropertyValue(validator).ToString(), Pattern).Success;
        }
    }

и затем сделать из него окончательное правило

 public class ValidateEmail : ValidateRegex
    {
        public ValidateEmail(string propertyName) :
            base(propertyName, @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")
        {
            Error = propertyName + " is not a valid email address";
        }

        public ValidateEmail(string propertyName, string errorMessage) :
            this(propertyName)
        {
            Error = errorMessage;
        }
    }

Валидатор может выглядеть примерно так:

public abstract  class Validator
    {
        // list of business rules

        List<ValidationRule> rules = new List<ValidationRule>();

        // list of validation errors (following validation failure)

        List<string> errors = new List<string>();


        // gets list of validations errors

        public List<string> Errors
        {
            get { return errors; }
        }


        // adds a business rule to the business object

        protected void AddRule(ValidationRule rule)
        {
            rules.Add(rule);
        }

        // determines whether business rules are valid or not.
        // creates a list of validation errors when appropriate

        public bool IsValid()
        {
            bool valid = true;

            errors.Clear();

            foreach (var rule in rules)
            {
                if (!rule.Validate(this))
                {
                    valid = false;
                    errors.Add(rule.Error);
                }
            }
            return valid;
        }
    }

Теперь вы можете использовать валидатор следующим образом (обратите внимание, конструктор, когда вы реализуете много разных правил валидации):

public class Person : Validator
    {
        public Person ()
        {
            AddRule(new ValidateEmail("Email"));

            AddRule(new ValidateId("MemberId"));

            AddRule(new ValidateRequired("Email"));
            AddRule(new ValidateLength("Email", 1, 100));


            AddRule(new ValidateRequired("CompanyName"));
            AddRule(new ValidateLength("CompanyName", 1, 40));

            AddRule(new ValidateRequired("City"));
            AddRule(new ValidateLength("City", 1, 15));

            AddRule(new ValidateRequired("Country"));
            AddRule(new ValidateLength("Country", 1, 15));
        }



        public int MemberId { get; set; }

        public string Email { get; set; }
        public string CompanyName { get; set; }
        public string City { get; set; }
        public string Country { get; set; }
        public int NumOrders { get; set; }
        public DateTime LastOrderDate { get; set; }
    }

Если вы сейчас вызываете метод IsValid () все ваши правила проверки выполняются.

Я чувствую, что это то, что вы хотите. Если вы не хотите ie передавать его объекту, вы можете попытаться создать автономный валидатор и объединить валидатор с классом, в котором он вам нужен, вместо того, чтобы выводить его из него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...