Возможно ли иметь в C # метод, который неявно десериализует аргумент, если он передается в виде строки JSON? - PullRequest
2 голосов
/ 29 июня 2019

Вопрос

У меня есть несколько ViewComponents, которые выглядят так:

public IViewComponentResult Invoke(BuyerViewModel buyer)

Я бы хотел, чтобы они могли принимать либо BuyerViewModel, либо строку JSONпредставляющий BuyerViewModel.Например, когда вы передаете JSON методу контроллера из JavaScript, если этот метод ожидает аргумент типа Dog, контроллер автоматически пытается десериализовать JSON в экземпляр Dog.Я пытаюсь имитировать это поведение.

Цель состоит в том, чтобы оба из этих примеров работали:

var buyer = new BuyerSummaryViewModel() { FirstName = "John" };
ViewComponent("Buyer", buyer);
ViewComponent("Buyer", "{\"Name\":\"John Smith\"}");

Почему?

Я пытаюсь создать универсальный метод JavaScript, который может извлекать ViewComponent на лету:

const fetchViewComponent = async (viewComponentName, viewModel) => {
  let data = { viewComponentName, viewModel };
  let html = await $.get(`/Order/FetchViewComponent`, data);
  return html;
}

//Get a BuyerViewComponent (example)
(async () => {
  let component = await fetchViewComponent("Buyer", `@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Buyer))`);
  console.log(component);
})();

Что я пробовал

Если я укажучто ViewModel BuyerViewModel, это работает.Строка JSON автоматически десериализуется в BuyerViewModel.

public class FetchViewComponentRequest
{
  public string ViewComponentName { get; set; }
  public BuyerViewModel ViewModel { get; set; }
  //     ^^^^^^^^^^^^^^
}

[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest request)
{
  return ViewComponent(request.ViewComponentName, request.ViewModel);
}

Проблема

Однако я не хочу указывать тип;Я хочу, чтобы это было generic .Итак, я попробовал это:

public class FetchViewComponentRequest
{
  public string ViewComponentName { get; set; }
  public string ViewModel { get; set; }
  //     ^^^^^^
}

[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest request)
{
  return ViewComponent(request.ViewComponentName, request.ViewModel);
}

Но, как и ожидалось, request.ViewModel не правильный тип;это заканчивается null в методе Invoke.Я надеялся, что есть флаг или что-то более глобальное, что я мог бы указать, чтобы он попытался неявно десериализовать эту строку в ожидаемый тип.

Есть ли более простой способ сделать это, который я не рассматривал?Или, если нет, то, как я это представляю, вообще возможно?

(я использую .NET Core 2.2 )

Ответы [ 3 ]

0 голосов
/ 30 июня 2019

Метод должен иметь некоторое представление о типе объекта, в который входит объект.

public T Convert<T>(dynamic obj) where T:class,new()
    {
        T myob = null;

        if (obj !=null && obj is T)
        {
            myob = obj as T;

        }
        else if (obj is string)
        {
            //convert to type
            myob = JsonConvert.DeserializeObject<T>(obj);

        }

        return myob;
    }
0 голосов
/ 30 июня 2019

Хорошо, я не уверен, что вам нужно.

Но здесь есть динамический способ сделать это без указания <T>.

//Assume that the namespace is DynamicTypeDemo
public class DynamicType {

// eg "DynamicTypeDemo.Cat, DynamicTypeDemo"
public string TypeName { get; set; } // the full path to the type

public string JsonString { get; set; } 

}

Теперь вы можете просто DeserializeObject

public object ToObject(DynamicType dynamicType){
var type = Type.GetType(dynamicType.TypeName);
// Here you could check if the json is list, its really upp to you
// but as an example, i will still add it
if (dynamicType.JsonString.StartsWith("[")) // its a list
    type =(List<>).MakeGenericType(type);
return JsonConvert.DeserializeObject(dynamicType.JsonString, type);
} 

А вот как это работает

var item = new DynamicType(){ 
     TypeName = "DynamicTypeDemo.Cat, DynamicTypeDemo", // or typeof(Cat).AssemblyQualifiedName
     JsonString = "{CatName:'Test'}"; // And for a list "[{CatName:'Test'}]"
 }

object dynamicObject= ToObject(item); // return it to the javascript
Cat cat = dynamicObject as Cat; // Cast it if you want
0 голосов
/ 30 июня 2019

Может быть, сделать ваш FetchViewComponentRequest универсальным?

    public class FetchViewComponentRequest<T>
    {
        public string ViewComponentName { get; set; }
        public T ViewModel { get; set; }
        //     ^^^^^^^^^^^^^^
    }

    [HttpGet]
    public IActionResult FetchViewComponent(FetchViewComponentRequest<BuyerViewModel> request)
    {
        return ViewComponent(request.ViewComponentName, request.ViewModel);
    }
...