是否可以在 C# 中有一个方法,如果参数作为 JSON 字符串传递,则该方法隐式反序列化参数?



问题

我有一些看起来像这样的视图组件:

public IViewComponentResult Invoke(BuyerViewModel buyer)

我希望它们能够接受BuyerViewModel或代表BuyerViewModel的JSON字符串。例如,当您将JSON从JavaScript传递到控制器方法时,如果该方法期望Dog类型的参数,则控制器会自动尝试将JSON验证为Dog实例。我正在尝试模仿这种行为。

目的是这些示例的两个有效:

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

为什么?

我正在尝试制作一种通用的JavaScript方法,该方法可以随时获取视图组件:

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

问题

但是,我不想指定类型;我希望这是通用。所以我尝试了:

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不是正确的类型;它在Invoke方法中结束null。我希望我可以指定一个标志或更多的全球内容,以便将此字符串隐含地化为预期类型。

有一个更简单的方法来做到这一点?或者,如果没有,我想设想的方式是可能的吗?

(我正在使用 .net Core 2.2 (

也许使您的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);
    }

该方法需要了解使对象进入的类型。

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

好吧,我不确定您需要什么。

,但这是一种动态的方法,而无需指定<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

最新更新