Лучший способ не повторяться при использовании X-editable в MVC ASP.net

#c# #javascript #asp.net-mvc-4 #x-editable

#c# #javascript #asp.net-mvc-4 #x-редактируемый

Вопрос:

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

Хорошо работает то, что вы можете прямо на месте обновлять свои элементы формы. Однако вам нужно будет создать действие для каждого отдельного элемента формы.

Пример :

 <a href="#" class="EditableSection" data-type="text" data-pk="@Model.id" data-name="Name" data-url="@Url.Action("_EditName", "User", new { Model.id})" data-title="Edit Name">@Model.Name</a>

<a href="#" class="EditableSection" data-type="text" data-pk="@Model.id" data-name="MiddleName" data-url="@Url.Action("_EditMiddleName", "User", new { Model.id})" data-title="Edit Middle Name">@Model.MiddleName</a>

<a href="#" class="EditableSection" data-type="text" data-pk="@Model.id" data-name="SurName" data-url="@Url.Action("_EditSurName", "User", new { Model.id})" data-title="Edit SurName">@Model.SurName</a>
 

В UserController я считаю, что мне нужно будет иметь 3 разных действия для каждого и большей части внутренних действий, похожих друг на друга, кроме элемента, который обновляется.

вот одно из действий :

         [HttpPost]
        public ActionResult _EditUserName(int id, int pk, string value, string name)
        {

            var user= this._userRep.First(o => o.id== pk);
            if (user!= null amp;amp; user.id== id)
            {
                if (!string.IsNullOrEmpty(value))
                {

                    user.UserName= value; //this is the only line changes from one to another action respectively   user.MiddleName = value or user.SurName = value 

                    this._userRep.Update(user);
                    this._userRep.SaveChanges();
                    return new HttpStatusCodeResult(HttpStatusCode.OK);
                }
                return Json(new { status = "error", msg = "You cannot leave blank" });

            }

            return  Json(new {status="error",msg="You cannot leave blank"});
        }
 

Я вижу 2 варианта улучшения, чтобы сделать код СУХИМ.

Первый — создать одно действие для каждого элемента формы и поместить всю общую задачу в отдельный метод для вызова каждого действия. (Тем не менее, я считаю, что слишком много ввода и беспорядка)

Второй вариант, на котором я сосредоточен, но я не мог понять, в чем я хотел бы получить вашу помощь здесь :

Создайте общее действие как _EditUserDetails и используйте условие что-то ниже :

         [HttpPost]
        public ActionResult _EditUserDetails(int id, int pk, string value, string name)
        {

            var user= this._userRep.First(o => o.id== pk);
            if (user!= null amp;amp; user.id== id)
            {
                if (!string.IsNullOrEmpty(value))
                {

                  if(name=user.UserName.toString())
                    user.UserName= value; 
                  else if(name=user.MiddleName.toString())
                      user.MiddleName= value; 
                  else if(name=user.MiddleName.toString())
                   user.SurName= value; 

                    this._userRep.Update(user);
                    this._userRep.SaveChanges();
                    return new HttpStatusCodeResult(HttpStatusCode.OK);
                }
                return Json(new { status = "error", msg = "You cannot leave blank" });

            }

            return  Json(new {status="error",msg="You cannot leave blank"});
        }
 

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

if(name=user.UserName.toString()) // name равно имени элемента формы. и я знаю user.UserName.toString() , что возвращает значение вместо ‘UserName’

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

Что было бы вашей лучшей практикой для этого?

Ответ №1:

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

 <a href="#" class="EditableSection" data-type="text" data-pk="@Model.id" id="Name" data-url="@Url.Action("InlineEdit", "User", new { Model.id})" data-title="Edit Name">@Model.Name</a>

<a href="#" class="EditableSection" data-type="text" data-pk="@Model.id" id="MiddleName" data-url="@Url.Action("InlineEdit", "User", new { Model.id})" data-title="Edit Middle Name">@Model.MiddleName</a>
 

xeditables передает идентификатор в параметре name, поэтому нет необходимости добавлять атрибут «data-name»

     [HttpPost,
    ValidateAntiForgeryToken]
    public ActionResult InlineEdit(int pk, string value, string name)
    {
        //
        // White list to prevent overposting
        string whitelist = "Name,MiddleName,SurName";
        if (!whitelist.Contains(name))
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest, string.Format("Invalid Field {0}", name));
        };

        var user= this._userRep.First(o => o.id== pk);;
        if (user == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest, string.Format("Resource not found"));
        }
        try
        {
                this.SetPropertyValue(user, name, value);
                this._userRep.Update(user);
                this._userRep.SaveChanges();
                return new HttpStatusCodeResult(HttpStatusCode.OK);
        }
        catch (DbEntityValidationException ex)
        {
            var error = ex.EntityValidationErrors.First().ValidationErrors.First();
            this.ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest, string.Format("{0}: {1}", error.PropertyName, error.ErrorMessage));
        } 
    }
 

Вот функция для установки свойства перед преобразованием его в соответствующий тип данных

     private Object SetPropertyValue(Object entity, string property, string value)
    {
        PropertyInfo propertyInfo = entity.GetType().GetProperty(property);

        if (propertyInfo != null)
        {
            Type t = propertyInfo.PropertyType;
            object d;
            if (t.IsGenericType amp;amp; t.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                if (String.IsNullOrEmpty(value))
                    d = null;
                else
                    d = Convert.ChangeType(value, t.GetGenericArguments()[0]);
            }
            else if (t == typeof(Guid))
            {
                d = new Guid(value);
            }
            else
            {
                d = Convert.ChangeType(value, t);
            }

            propertyInfo.SetValue(entity, d, null);
        }
        return entity;
    }
 

Много кода для трех полей (в этом случае я бы предпочел использовать 3 действия пользователя). Очень полезно, если у вас много полей, которые вы хотите обновить.

Комментарии:

1. Чтобы получить ValidateAntiForgeryToken woring, его нужно использовать @Html.AntiForgeryToken() . Посмотрите на эту проблему