4

我怎样才能在我的函数中开始填充它应该返回的类的参数,但是如果发生异常,我将返回我的错误类呢?

public **** function()
    {
        try
        {
            Articles articles = new Articles();
            articles.articleid = 234;
            articles.articlename = "Milk";
            articles.deleted = 0;

            //continue fill Articles 
            //and an exception occurs


            return articles;

        }
        catch (Exception e)
        {
            Errors Error = new Errors();
            Error.exceptionmessage = e.Message;
            Error.exceptionname = e.ToString();
            Error.httpcode = 500;


            return Error;
        }
    }

这是可能的,而且是一件好事吗?或者我应该用我的错误类扩展所有返回类,即使我会返回很多带有分配空值的信息。我想发送尽可能少的数据,如果我的功能失败,我只会发回错误。

更新

抱歉没有提供足够的关于我的情况的信息这是我想在网络服务中使用的功能

[OperationContract]
    [WebGet(
        ResponseFormat = WebMessageFormat.Json,
        RequestFormat = WebMessageFormat.Json)]
    **** Function();

所以我不认为我可以抛出异常。如果一切顺利,我想返回一类文章,所以我不必将我的数据转换为 JSON,但如果出现问题,我想向客户端发送 http 代码 500 内部服务器错误。我尚未阅读所有答案,但我认为我必须将我的错误类包含在我所有其他返回类中,以便客户现在可以在出现问题时?

4

7 回答 7

10

更新:

这可以让您更深入地了解您想要做什么。由于你不能抛出异常,你应该有一个基结果类。我通常对通过 javascript 调用的 WCF 方法执行此操作,因为它不能很好地处理异常。

所以你会想要一个像这样的基类:

[DataContract]
public class AjaxResult
{
    public static AjaxResult GetSuccessResult()
    {
        return new AjaxResult();
    }

    [DataMember]
    public int Status { get; set; }
    [DataMember]
    public string Error { get; set; }
}

然后您可以继承它,添加您想要返回的任何数据。此示例返回单个产品对象和验证错误列表。

[DataContract]
public class SingleProductResult : AjaxResult
{
    [DataMember]
    public Product Data { get; set; }
    [DataMember]
    public IList<int> ValidationErrors { get; set; }
}

您还可以选择创建一个通用包装器,这样您就不必在方法中编写太多代码。我通常将它放在一个基类中,并让所有 WCF 服务都从该类继承。

protected T PerformAjaxOperation<T>(Func<T> action) where T : AjaxResult, new()
{
    try
    {
        return action();
    }
    catch (AccessDeniedException ade)
    {
        // -- user tried to perform an invalid action
        return new T()
        {
            Status = AjaxErrorCodes.AccessDenied,
            Error = ade.ToString()
        };
    }
    catch (Exception ex)
    {
        return new T()
        {
            Error = ex.ToString(),
            Status = 1
        };
    }
}

然后像这样使用它:

public SingleProductResult GetProduct(int productId)
{
    return PerformAjaxOperation(() =>
    {
        return retval = new SingleProductResult()
            {
                Data = ProductServiceInstance.GetProduct(productId)
            };
    });
}
public AjaxResult DeleteProduct(int productId)
{
    return PerformAjaxOperation(() => {
        ProductServiceInstance.DeleteProduct(productId);
        return AjaxResult.GetSuccessResult();
    });
}

因此,如果一切顺利,error 将为 0,message 将为空。如果抛出异常,那么它将被PerformAjaxOperation()函数捕获并填充到AjaxResult对象(或其派生对象)中并返回给客户端。


上一个答案:

我不认为这是一个好主意。您可以做的是通过创建一个类来创建自定义异常,该类继承自Exception并添加要保存的属性。然后,当发生异常时,您只需捕获它并将其与其他详细信息一起填充到这个新异常中。然后抛出这个异常。然后,您可以在更高级别捕获此异常并显示正确的消息。

一个例子:

public IList<Articles> GetArticles()
{
    try
    {
        return GetSomeArticlesFromDatabase();
    }
    catch (Exception innerException)
    {
        throw new MyCustomException("some data", 500, innerException);
    }
}
public class MyCustomException : Exception
{
    public int HttpCode { get; set; }
    public MyCustomException(string errorMessage, int httpCode, Exception innerException)
        : base(errorMessage, innerException) {
            HttpCode = httpCode;
    }
}
public void EntryPoint()
{
    try
    {
        DoSomething();
        var result = GetArticles();
        DoSomething();
        DisplayResult(result);
    }
    catch (MyCustomException ex)
    {
        ReturnHttpError(ex.Message, ex.HttpCode);
    }
}
于 2013-07-17T08:04:05.047 回答
8

我会诚实地建议不要做你的建议。相反,要么使用现有Exception类型,要么创建一个新的子类Exception并抛出它。如果需要,您甚至可以在新异常中保留导致异常的信息InnerException


但是,如果这种情况不需要例外(您没有提供有关您正在做什么的足够详细信息),您可以创建一个Result包含错误/警告信息的类。不过,这种事情更适合警告。也就是说,阻止事情继续进行的不是错误条件(异常),而是调用代码可以选择忽略而不会产生严重副作用的消息。

例如:

class Result<T>
{
    public Result(T Value, Errors Errors = null)
    {
        this.Value = Value;
        this.Errors = Errors;
    }

    public T Value {get; private set;}

    public Errors Errors {get; private set;}
}

用法(根据您的示例代码):

public Result<Articles> function()
{
    try
    {
        Articles articles = new Articles();
        articles.articleid = 234;
        articles.articlename = "Milk";
        articles.deleted = 0;

        //continue fill Articles 
        //and an exception occurs


        return new Result(articles);

    }
    catch (Exception e)
    {
        Errors Error = new Errors();
        Error.exceptionmessage = e.Message;
        Error.exceptionname = e.ToString();
        Error.httpcode = 500;


        return new Result<Articles>(null, Error);
    }
}
于 2013-07-17T08:03:33.397 回答
1

如果class1并且class2有一个通用的基类型或通用接口,请使用它。但在这种情况下,您可以创建一个包装类来封装这两种结果类型,如下所示:

class MethodResult<T>
{
    public T Result { get; private set; }
    public Errors Errors { get; private set; }

    public MethodResult(T result) { this.Result = result; }
    public MethodResult(Errors errors) { this.Errors = errors; }
}

public MethodResult<Articles> MyMethod()
{
    try
    {
        ... 
        return new MethodResult<Articles>(articles);
    }
    catch(Exception e)
    {
        ... 
        return new MethodResult<Articles>(errors);
    }
}
于 2013-07-17T08:03:54.030 回答
1

根据问题中的其他信息,由于这是 WCF 服务,您可以抛出WebFaultException

public Articles function()
{
    try
    {
        Articles articles = new Articles();
        articles.articleid = 234;
        articles.articlename = "Milk";
        articles.deleted = 0;

        //continue fill Articles 
        //and an exception occurs


        return articles;

    }
    catch (Exception e)
    {
        throw new WebFaultException(System.Net.HttpStatusCode.InternalServerError)
        {
            Message = e.Message
        };
    }
}
于 2013-07-17T09:08:11.327 回答
0

你可以试试out关键字,

public Articles function(out Error err)
    {
        Articles articles = null;
        err = null;
        try
        {
            articles = new Articles();
            articles.articleid = 234;
            articles.articlename = "Milk";
            articles.deleted = 0;
            // Set your article values

        }
        catch (Exception e)
        {
            Errors ex = new Errors();
            ex.exceptionmessage = e.Message;
            ex.exceptionname = e.ToString();
            ex.httpcode = 500;

            err = ex;
        }
        return articles;
    }
于 2013-07-17T08:00:54.830 回答
0

其他答案处理此问题的方式涉及如何使用接口和子类定义这两个类的技术方法。

但是,从根本上说,您实际上是在解决错误的问题。您仍然需要在调用者中编写代码来区分这两种类型的对象,并记录您的函数的工作方式。

就个人而言,我会为您可能正在处理的错误类型创建一个新的异常类,然后抛出它,例如:

public class InvalidArticleException: Exception {
    public string ExceptionMessage { get; set; }
    public string ExceptionName { get; set; }
    public int HttpCode { get; set; }

}

public **** function()
{
    try
    {
        // DO STUFF
        return articles;
    }
    catch (InvalidArgumentException e)
    {
        throw new InvalidArticleException() {
            ExceptionMessage = e.Message,
            ExceptionName = e.ToString(),
            HttpCode = 500
        }
    }
    catch (Exception ex) {   // Not actually required; left in for future debugging
       throw ex;             
    }
}

然后,调用者将能够捕获异常并检查它的错误详细信息,代码与处理返回文章的代码保持分离。

于 2013-07-17T08:11:06.183 回答
-1

我不确定您为什么要吞下这些例外,但是如果您这样做,那么这种行为会使两种类型的返回类型都通用。这两个类都继承自对象,因此您可以将方法签名更改为public object function()

于 2013-07-17T08:03:36.327 回答