ASP.NET Core [FromBody] и привязка MVC 5 - PullRequest
0 голосов
/ 29 октября 2018

Я получил приложение MVC 5, которое я портирую на asp.net Core.

При вызове приложения MVC к контроллеру мы используем ресурс AngularJS $ (отправка JSON), и мы размещаем данные, выполняя:

ressource.save({ entries: vm.entries, projectId: vm.project.id }).$promise...

, который отправит тело в формате JSON, например:

{
  entries: 
  [
    {
      // lots of fields
    }
  ],
  projectId:12
}

контроллер MVC выглядел так:

[HttpPost]
public JsonResult Save(List<EntryViewModel> entries, int projectId) {
// code here
}

Как я могу повторить такое же поведение с .NET Core, так как у нас не может быть несколько [FromBody]

Ответы [ 3 ]

0 голосов
/ 30 октября 2018

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

[HttpPost("save/{projectId}")]
public JsonResult Save(int projectId, [FromBody] dynamic entries) {
// code here
}
0 голосов
/ 30 октября 2018

Это все еще грубо, но я сделал Фильтр, чтобы имитировать функцию.

public class OldMVCFilter : IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
    }
    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.HttpContext.Request.Method != "GET")
        {
            var body = context.HttpContext.Request.Body;
            JToken token = null;
            var param = context.ActionDescriptor.Parameters;

            using (var reader = new StreamReader(body))
            using (var jsonReader = new JsonTextReader(reader))
            {
                jsonReader.CloseInput = false;
                token = JToken.Load(jsonReader);
            }
            if (token != null)
            {
                var serializer = new JsonSerializer();
                serializer.DefaultValueHandling = DefaultValueHandling.Populate;
                serializer.FloatFormatHandling = FloatFormatHandling.DefaultValue;

                foreach (var item in param)
                {
                    JToken model = token[item.Name];

                    if (model == null)
                    {
                        // try to cast the full body as the current object
                        model = token.Root;
                    }

                    if (model != null)
                    {
                        model = this.RemoveEmptyChildren(model, item.ParameterType);
                        var res = model.ToObject(item.ParameterType, serializer);
                        context.ActionArguments[item.Name] = res;
                    }
                }
            }
        }
    }
    private JToken RemoveEmptyChildren(JToken token, Type type)
    {
        var HasBaseType = type.GenericTypeArguments.Count() > 0;
        List<PropertyInfo> PIList = new List<PropertyInfo>();
        if (HasBaseType)
        {
            PIList.AddRange(type.GenericTypeArguments.FirstOrDefault().GetProperties().ToList());
        }
        else
        {
            PIList.AddRange(type.GetTypeInfo().GetProperties().ToList());
        }

        if (token != null)
        {
            if (token.Type == JTokenType.Object)
            {
                JObject copy = new JObject();
                foreach (JProperty jProp in token.Children<JProperty>())
                {
                    var pi = PIList.FirstOrDefault(p => p.Name == jProp.Name);
                    if (pi != null) // If destination type dont have this property we ignore it
                    {
                        JToken child = jProp.Value;
                        if (child.HasValues)
                        {
                            child = RemoveEmptyChildren(child, pi.PropertyType);
                        }
                        if (!IsEmpty(child))
                        {
                            if (child.Type == JTokenType.Object || child.Type == JTokenType.Array)
                            {
                                // nested value has been checked, we add the object
                                copy.Add(jProp.Name, child);
                            }
                            else
                            {
                                if (!pi.Name.ToLowerInvariant().Contains("string"))
                                {
                                    // ignore empty value when type is not string
                                    var Val = (string)child;
                                    if (!string.IsNullOrWhiteSpace(Val))
                                    {
                                        // we add the property only if it contain meningfull data
                                        copy.Add(jProp.Name, child);
                                    }
                                }
                            }
                        }
                    }
                }
                return copy;
            }
            else if (token.Type == JTokenType.Array)
            {
                JArray copy = new JArray();
                foreach (JToken item in token.Children())
                {
                    JToken child = item;
                    if (child.HasValues)
                    {
                        child = RemoveEmptyChildren(child, type);
                    }
                    if (!IsEmpty(child))
                    {
                        copy.Add(child);
                    }
                }
                return copy;
            }
            return token;
        }
        return null;
    }

    private bool IsEmpty(JToken token)
    {
        return (token.Type == JTokenType.Null || token.Type == JTokenType.Undefined);
    }
}
0 голосов
/ 29 октября 2018

Как указано в комментарии, одним из возможных решений является объединение свойств, которые вы публикуете, в один класс модели.

Что-то вроде следующего должно помочь:

public class SaveModel
{
    public List<EntryViewModel> Entries{get;set;}

    public int ProjectId {get;set;}
}

Не забудьте украсить модель атрибутом [FromBody]:

[HttpPost]
public JsonResult Save([FromBody]SaveViewModel model) 
{
    // code here
}

Надеюсь, это поможет!

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