2

質問が長すぎて、達成しようとしていることが失われた可能性があるため、質問を書き直しました。

私はこのコードをメモ帳で書いたので、間違いやうまくいかないものがあるかもしれませんが、私のオプションが何であるかを説明するためのものです。

// I wrap all code send back from service layer to controller in this class.
  public class ResponseResult
    {

        public ResponseResult()
        {
            Errors = new Dictionary<string, string>();
            Status = new ResponseBase();
        }

        public void AddError(string key, string errorMessage)
        {
            if (!Errors.ContainsKey(key))
            {
                Errors.Add(key, errorMessage);
            }
        }

        public bool IsValid()
        {
            if (Errors.Count > 0)
            {
                return false;
            }

            return true;
        }


        public Dictionary<string, string> Errors { get; private set; }


        public ResponseBase Status { get; set; }
    }

    public class ResponseResult<T> : ResponseResult
    {

        public T Response { get; set; }
    }

    public class ResponseBase
    {
        public HttpStatusCode Code { get; set; }
        public string Message { get; set; }
    }

オプション1(私が今使っているもの)

//controller
    public HttpResponseMessage GetVenue(int venueId)
            {
                if (venueId == 0)
                {
                    ModelState.AddModelError("badVenueId", "venue id must be greater than 0");

                if (ModelState.IsValid)
                {
                    var venue = venueService.FindVenue(venueId);
                    return Request.CreateResponse<ResponseResult<Venue>>(venue.Status.Code, venue);
                }

                // a wrapper that I made to extract the model state and try to make all my request have same layout.
                var responseResult = new ResponseResultWrapper();
                responseResult.Status.Code = HttpStatusCode.BadRequest;
                responseResult.Status.Message = GenericErrors.InvalidRequest;
                responseResult.ModelStateToResponseResult(ModelState);

                return Request.CreateResponse<ResponseResult>(responseResult.Status.Code, responseResult);
            }

// service layer        
             public ResponseResult<Venue> FindVenue(int venueId)
            {
                ResponseResult<Venue> responseResult = new ResponseResult<Venue>();

                try
                {
                    // I know this check was done in the controller but pretend this is some more advanced business logic validation.
                    if(venueId == 0)
                    {
                       // this is like Model State Error in MVC and mostly likely would with some sort of field.
                       responseResult.Errors.Add("badVenueId", "venue id must be greater than 0");
                       responseResult.Status.Code = HttpStatusCode.BadRequest;
                    }

                    var venue = context.Venues.Where(x => x.Id == venueId).FirstOrDefault();

                    if(venue == null)
                    {
                        var foundVenue = thirdPartyService.GetVenue(venueId);

                        if(foundVenue == null)
                        {
                           responseResult.Status.Code = HttpStatusCode.NotFound;
                           responseResult.Status.Message = "Oops could not find Venue";

                           return responseResult;
                        }
                        else
                        {
                           var city = cityService.FindCity(foundVenue.CityName);

                           if(city == null)
                           { 
                              city = cityService.CreateCity(foundVenue.CityName);

                              if(city.Response == null)
                              {
                                 responseResult.Status.Code = city.Status.Code;
                                 responseResult.Status.Message = city.Status.Message;

                                 return responseResult;
                              }

                              CreateVenue(VenueId, city.Response, foundVenue.Name);

                               responseResult.Status.Code = HttpStatusCode.Ok;
                               // I don't think I would return a success message here as the venue being displayed back to the user should be good enough.
                               responseResult.Status.Message = "";

                               reponseResult.Response = foundVenue;
                           }
                        }

                        return responseResult;
                    }

                }
                catch (SqlException ex)
                {
                    ErrorSignal.FromCurrentContext().Raise(ex);
                    responseResult.Status.Code = HttpStatusCode.InternalServerError;
                    responseResult.Status.Message = GenericErrors.InternalError;

                    // maybe roll back statement here depending on the method and what it is doing.
                }
               // should I catch this, I know it should be if you handle it but you don't want nasty messages going back to the user.
                catch (InvalidOperationException ex)
                {
                    ErrorSignal.FromCurrentContext().Raise(ex);
                    responseResult.Status.Code = HttpStatusCode.InternalServerError;
                    responseResult.Status.Message = GenericErrors.InternalError;
                }
               // should I catch this, I know it should be if you handle it but you don't want nasty messages going back to the user.
                catch (Exception ex)
                {
                    ErrorSignal.FromCurrentContext().Raise(ex);
                    responseResult.Status.Code = HttpStatusCode.InternalServerError;
                    responseResult.Status.Message = GenericErrors.InternalError;
                }

                return responseResult;
            }

// another service layer. 

        // it is ResponseResult<City> and not city because I could have a controller method that directly calls this method.
            // but I also have a case where my other method in another service needs this as well.
            public ResponseResult<City> CreateCity(string CityName)
            {
               ResponseResult<City> responseResult = new ResponseResult<City>();
               try
               {
                   City newCity = new City {  Name = "N" };
                   context.Cities.Add(newCity);
                   context.SaveChanges();

                    responseResult.Status.Code = HttpStatusCode.Ok;
                    responseResult.Status.Message = "City was succesfully added";
               }           
               // same catch statmens like above
               catch (SqlException ex)
                {
                    ErrorSignal.FromCurrentContext().Raise(ex);
                    responseResult.Status.Code = HttpStatusCode.InternalServerError;
                    responseResult.Status.Message = GenericErrors.InternalError;

                    // maybe roll back statement here depending on the method and what it is doing.
                }
                return responseResult;
            }

ご覧のとおり、メソッドはすべてステータス コードでラップされています。これは、メソッドが公開されているコントローラーによって直接呼び出される可能性があるためです。FindCity() と CreateVenue() もこのラッピングを持つことができます。

オプション 2

   public HttpResponseMessage GetVenue(int venueId)
        {
            try
            {
                if (venueId == 0)
                {
                    ModelState.AddModelError("badVenueId", "venue id must be greater than 0");

                if (ModelState.IsValid)
                {
                    var venue = venueService.FindVenue(venueId);
                    return Request.CreateResponse<ResponseResult<Venue>>(HttpSatusCode.Ok, venue);
                }

                // a wrapper that I made to extract the model state and try to make all my request have same layout.
                var responseResult = new ResponseResultWrapper();
                responseResult.Status.Code = HttpStatusCode.BadRequest;
                responseResult.Status.Message = GenericErrors.InvalidRequest;
                responseResult.ModelStateToResponseResult(ModelState);

                return Request.CreateResponse<ResponseResult>(responseResult.Status.Code, responseResult);
            }
            catchcatch (SqlException ex)
            {
               // can't remember how write this and too tried to look up.
               return Request.CreateResponse(HttpStatusCode.InternalServerError;, "something here");
            }
        }

 public Venue FindVenue(int venueId)
        {
            try
            {
                // how to pass back business logic error now without my wrapper?
                if(venueId == 0)
                {
                   // what here?
                }

                var venue = context.Venues.Where(x => x.Id == venueId).FirstOrDefault();

                if(venue == null)
                {
                    var foundVenue = thirdPartyService.GetVenue(venueId);

                    if(foundVenue == null)
                    {
                       // what here?
                    }
                    else
                    {
                       var city = cityService.FindCity(foundVenue.CityName);

                       if(city == null)
                       { 
                          city = cityService.CreateCity(foundVenue.CityName);

                          if(city  == null)
                          {
                             // what here?
                          }

                          CreateVenue(VenueId, city.Response, foundVenue.Name);


                       }
                    }

                    return venue;
                }

            }
            catch (SqlException ex)
            {
                // should there be a try catch here now? 
                // I am guessing I am going to need to have this here if I need to do a rollback and can't do it in the controller

                // throw exception here. Maybe this won't exist if no rollback is needed.
            }
            return null;
        }

        public City CreateCity(string CityName)
        {
           // if it crashes something I guess will catch it. Don't think I need to rollback here as only one statement being sent to database.
            City newCity = new City {  Name = "N" };
            context.Cities.Add(newCity);
            context.SaveChanges();

            return newCity;            
        }

オプション 2 でわかるように、ロールバックのために try catch でラップする必要があるかもしれませんが、高度なビジネス検証を処理する方法がわかりません。

また、コントローラー内のすべてをキャッチし、バニラオブジェクトを送り返すことで(ラッパーなしで)、細粒度のHttpStatusコードを実行する方法がわかりません(notFound、Createなど)

4

6 に答える 6

0

何か問題が発生したとコードが判断した場合は常に例外をスローします。

エンドユーザーによって直接呼び出されるメソッドの例外を常に処理する必要があります。これは、コードに特定の処理がない予期しないエラーに対応するためです。一般的な処理コードは通常、エラーをログに記録し、予期しないエラーが発生したことをユーザーに知らせることを含む場合と含まない場合があります。

しかし、事前に予想できるエラーがある場合は、アプリケーションがエラーから「回復」して続行できるように、コードの下位、つまりエラーが発生したポイントに近い場所でこれらを処理したいことがよくあります。

于 2013-10-10T00:28:35.987 に答える
-2

すべてのレベルで try catch を使用し、バブルアップします。必要に応じて、エラーをファイルまたはデータベースに記録します。タブ区切りのテキストファイルを使用しています。各レベルでのキャプチャ 1. モジュール名 (これを取得するには C# 提供のメソッドを使用) 2. メソッド名 3. 実行中のコード (ユーザー作成 - 「データベースへの接続」) 4. エラー番号 5. エラーの説明 6. 実行中のコード (ユーザー作成 - 「データベースへのアクセス」) 7. エンド ユーザーのエラー番号 8. エンド ユーザーのエラーの説明 さらに、次のような一意の識別子も渡します - Web の場合はセッション ID、ログインしたユーザー ID、ユーザー名 (利用可能)

私は常に Exception catch ブロックを持っています。ここでは、エラー番号を -0 に設定し、例外オブジェクトからのメッセージをエラーの説明として設定しています。SQL Server 関連の場合 - SQL 例外をキャプチャします。これによりエラー番号が生成されます-私はそれを使用します。

これをもう少し伸ばしたいと思います。

于 2013-10-10T01:18:07.660 に答える