C# 使用c中未知异常类型的泛型初始化#

C# 使用c中未知异常类型的泛型初始化#,c#,json,generics,exception,exception-handling,C#,Json,Generics,Exception,Exception Handling,在我的应用程序webapi中,我有一个异常过滤器,假设它可以捕获任何异常并将其传输到响应包装器类中的客户端。 我的目标是使异常以正确的类型传输,以便客户机可以重建并重新抛出它 以下是异常捕捉器的代码: public override void OnException(HttpActionExecutedContext actionExecutedContext) { HttpStatusCode OutputHttpCode = HttpStatusCode.Inter

在我的应用程序
webapi
中,我有一个异常过滤器,假设它可以捕获任何异常并将其传输到响应包装器类中的客户端。 我的目标是使异常以正确的类型传输,以便客户机可以重建并重新抛出它

以下是异常捕捉器的代码:

public override void OnException(HttpActionExecutedContext actionExecutedContext)
    {

        HttpStatusCode OutputHttpCode = HttpStatusCode.InternalServerError;
        var exceptionType = actionExecutedContext.Exception.GetType();

        if (exceptionType == typeof(InvalidIDException))
        {
            OutputHttpCode = HttpStatusCode.Unauthorized;
        }

        //this way of getting type didnt work for me either
        //var exceptionType = typeof(RestErrorResponse<>).MakeGenericType(actionExecutedContext.Exception.GetType());

        actionExecutedContext.Response = new HttpResponseMessage()
        {
            Content = new StringContent(JsonConvert.SerializeObject(
                //this will not compile here, saying t is a variable but used like a type.
                //If i use generic "Exception" instead everything is working fine,
                //but it will be interpreted as generic exception on client side and
                //could not be handled properly if i rethrow it directly
                new RestErrorResponse<exceptionType> () //Exception will compile
                {
                    Content = null,
                    Status = RestStatus.Error,
                    Exception = actionExecutedContext.Exception
                }
                ),
                    System.Text.Encoding.UTF8, "application/json"),

            StatusCode = OutputHttpCode
        };

        base.OnException(actionExecutedContext);
    }
我的目标是:

{
  "InvalidLoginException": {
    "ClassName": "InvalidLoginException",
    "Message": "Invalid User Name",
    "Data": {},
    "InnerException": null,
    "HelpURL": null,
    "StackTraceString": "....",
    "RemoteStackTraceString": null,
    "RemoteStackIndex": 0,
    "ExceptionMethod": "....",
    "HResult": -2147024809,
    "Source": "DB",
    "WatsonBuckets": null,
    "ParamName": null
  },
  "Status": {
    "Verbal": "Error",
    "Code": 1074
  },
  "Content": null
}

RestErrorResponse是您控制的类吗?如果是这样,它真的必须是通用的吗?考虑这一点:

public class RestErrorResponse : RestResponse<Object> {
    public object Exception { get; set; }
}
如果无法更改它,则需要反射来创建RestErrorResponse实例。例如:

 var responseType = typeof(RestErrorResponse<>).MakeGenericType(exceptionType);
 dynamic response = Activator.CreateIntance(type);
 response.Content = null;
 response.Status = RestStatus.Error;
 response.Exception = actionExecutedContext.Exception;
var responseType=typeof(RestErrorResponse)。MakeGenericType(exceptionType);
动态响应=Activator.CreateIntance(类型);
response.Content=null;
response.Status=RestStatus.Error;
response.Exception=actionExecutedContext.Exception;

为什么它必须是通用的。所有异常都将强制转换为
异常
。另外,如果不动态生成JSON,就无法生成这样的对象名变量。我认为可以使用
GenericTypeNameContractResolver
JsonPropertyGenericTypeNameAttribute
from。您需要添加属性
[JsonPropertyGenericTypeName(0)]public E myException{get;set;}
。请参阅和,以获取最近使用小提琴的示例。或者,您可以使用
[JsonProperty(typenameholding=typenameholding.Auto)]
标记
public E myException{get;set;}
。为了安全起见,您还应该将
T
限制为
Exception
类型。RestErrorResponse在我的控制下,如果不使用泛型更好,我可以更改它,但是如果我只使用“Exception”,JSON会将其反序列化为泛型异常,我将无法在更改它时重新显示它(参见更新答案的第一部分)但是在客户端重新创建相同的异常类型怎么样?这样做只是将其反序列化为“异常”,而不是“InvalidLoginException”如果您在反序列化方面有问题,请询问另一个问题。请参阅示例。但请注意,序列化/反序列化异常存在文档化问题,主要是因为并非所有异常都正确实现(尤其是第三方库)。YMMV。
public class RestErrorResponse : RestResponse<Object> {
    public object Exception { get; set; }
}
var response = new RestErrorResponse 
{
     // other properties
     Exception = actionExecutedContext.Exception
}
 var responseType = typeof(RestErrorResponse<>).MakeGenericType(exceptionType);
 dynamic response = Activator.CreateIntance(type);
 response.Content = null;
 response.Status = RestStatus.Error;
 response.Exception = actionExecutedContext.Exception;