首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Mapster从动态类型到class<T>

Mapster从动态类型到class<T>
EN

Stack Overflow用户
提问于 2022-02-11 10:02:59
回答 1查看 1K关注 0票数 1

我必须管理对服务的大量API调用,并且所有响应消息都有一个公共结构,除了"data“字段,该字段根据调用的端点和调用是否成功而变化。为了找到一种聪明地管理整个情况的方法,我用泛型和Mapster提供了一个令人满意的解决方案。这是一个典型的响应消息:

代码语言:javascript
复制
    {
       "type": "send",
       "datetime": "2022-02-21",
       "correlation_id": "dc659b16-0781-4e32-ae0d-fbe737ff3215",
       "data": {
        "id": 22,
        "description": "blue t-shirt with stripes",
        "category": "t-shirt",
        "size": "XL"
       }
    }

数据字段是完全可变的,有时是一级结构,有时是多级结构,有时是数组,有时是简单字符串,有时是空值。显然,响应消息是已知的,并且取决于被调用的端点,所以我知道当我进行调用时会期望什么,但是在这种情况下,结构仍然可以改变。如果调用失败且出现错误,则仍将从端点返回200,但响应如下:

代码语言:javascript
复制
    {
       "type": "error",
       "datetime": "2022-02-21",
       "correlation_id": "dc659b16-0781-4e32-ae0d-fbe737ff3215",
       "data": {
        "id": 1522,
        "description": "product code not found",
       }
    }

为了寻找一个优雅而简洁的解决方案,用一个方法来管理所有的案例,我找到了一个解决方案:这些是我的模型:

代码语言:javascript
复制
    public class Response<T> where T : class
    {
        public string type { get; set; }
        public T data { get; set; } = null;
        public Error Error { get; set; } = null;
        public bool IsError => Error != null;
        public string ErrorMessage => IsError ? $"An error occurred. Error code {Error.id} - {Error.description}" : "";
    }
    public class Customer
    {
        public int customerId { get; set; }
        public string name { get; set; }
    }
    public class Supplier
    {
        public int supplierId { get; set; }
        public string company { get; set; }
    }
    public class Error
    {
        public int id { get; set; }
        public string description { get; set; }
    }

这是我管理所有反序列化的功能:

代码语言:javascript
复制
    private static Response<T> GetData<T>(string json) where T : class
    {
        //Deserialize the json using dynamic as T so can receive any kind of data structure
        var resp = JsonConvert.DeserializeObject<Response<dynamic>>(json);
        var ret = resp.Adapt<Response<T>>();
    
        if (resp.type == "error")
        {
            //Adapt the dynamic to Error property
            ret.Error = ((object)resp.data).Adapt<Error>();
            ret.data = null;
        }
        return ret;
    }

所以我用这种方式调用我的函数:

代码语言:javascript
复制
    var customerData = GetData<Customer>("{\"type\":\"send\", \"data\": {\"id\":1, \"name\": \"John Ross\"}}");
    if (customerData.IsError)
        Console.WriteLine($"ERROR! {customerData.ErrorMessage}");
    else
        Console.WriteLine($"The response is OK. Customer name is {customerData.data.name}");

正如您所看到的,所采用的解决方案是优雅的,而且效果很好。我还没有找到解决方案的唯一问题是,如果我尝试将错误的json插入T类型,Mapster.Adapt就不会失败,因此,如果我在供应商类中反序列化客户的json,我就不会注意到这个问题。

在Mapster中是否有一种方法可以知道我试图适应的对象是否与目标类型不兼容?所以我可以提出一个例外,我的程序将是完美的。

下面是一个带有工作示例https://github.com/mmassari/MapDynamicWIthMapster的回购

谢谢

EN

回答 1

Stack Overflow用户

发布于 2022-02-13 11:18:19

您正在尝试的解决方案可能看起来很优雅,但实际上您可能会引入一个code smell,它可能会在将来很难捕获bug。

您可能需要重新考虑使用有关端点的知识将响应反序列化为其正确的响应类型。这是一个很好的实践,对您自己和未来的开发人员来说都很容易理解和维护。

对于有问题的“未找到的产品代码”响应,您可以添加一个验证步骤,将JSON响应反序列化到JObject类型的对象,您可以安全地查询该对象,以检查是否存在已知的错误消息。

下面是一个简单的例子:

代码语言:javascript
复制
private static void ValidateResponse(string json)
{
    var knownErrors = new List<string>()
    {
        "Product code not found",
        "Customer does not exist",
        "Other known errors here"
    };

    var jobj = JsonConvert.DeserializeObject<JObject>(json);
    var error = jobj.SelectToken("data.description");
    if (error != null)
    {
        var errorMessage = error.Value<string>();
        if (knownErrors.Contains(errorMessage))
        {
            throw new ApplicationException(errorMessage);
        }
    }
}

您可能需要考虑修整和正常化套管,以避免被错误消息中的小变化抛出。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71078222

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档