1

LinqToSql を使用して ASP.NET MVC プロジェクトに取り組んできました。アプリケーションには、UI、ビジネス、データの 3 つのレイヤーがあります。

ここ数日、私は Excel ファイルのアップロードを実装していました (私はまだ実装しています)。したがって、私のコントローラーはアップロードされたファイルを受け取り、いくつかのことを行い、情報をビジネスに渡し、次にデータに渡します。しかし、その展開に伴い、いくつかの疑問が浮かび上がってきました。

これが私の疑問のいくつかです(箇条書きが最も簡単な方法だと思います):

  1. Excel ファイルを検証する必要があります。アプリケーションは、ワークシートの値が正しいかどうかを検証し、正しい場合はデータベースに挿入/更新する必要があります。コントローラーまたはビジネスで Excel を検証する必要がありますか?

  2. このExcelはDBにデータを挿入するかもしれnew Product(); ません. UI からビジネスにオブジェクトを渡す方が良いですか、それともすべてのクラス プロパティを渡してビジネスでオブジェクトを作成する方が良いですか?

  3. この Excel アクションには、ワークシートが最後に達したかどうかの確認、セルに値があるかどうかの確認、アップロードされたファイルの DataTable の生成など、いくつかのヘルパー メソッドがあります。これらのヘルパー メソッドはどこに配置する必要がありますか? 現時点では、UI レイヤー (コントローラーと同じ) にあります。

  4. Excel のことは忘れて、単純な製品フォーム ページを想像してみてください。POST で、Controller は FormCollection を受け取ります。この FormCollection を Controller で処理する必要がありますか、それとも Business に渡して Business ですべて処理する必要がありますか?

質問が多くてすみません。また、コードをリファクタリングしようとしていますが、「Fat Controller」の問題がすぐに発生します。

前もって感謝します!

4

1 に答える 1

2

あなたは確かに太ったコントローラーを持つことを避けるべきです。しかし、いつものように、言うは易く行うは難しです。

それでは、例を挙げてあなたの質問に答えてみましょう。FormCollectionいつものように、ユーザーがこのアクションに送信するデータを表すビュー モデルを設計することから始めます (弱く型付けされたやは使用しないでくださいViewData) 。

public class UploadViewModel
{
    [Required]
    public HttpPostedFileBase File { get; set; }
}

次に、コントローラーに進みます。

public ProductsController: Controller
{
    private readonly IProductsService _service;
    public ProductsController(IProductsService service)
    {
        _service = service;
    }

    public ActionResult Upload()
    {
        var model = new UploadViewModel();
        return View(model);
    }

    [HttpPost]
    public ActionResult Upload(UploadViewModel model)
    {
        if (!ModelState.IsValid)
        {
            // The model was not valid => redisplay the form 
            // so that the user can fix his errors
            return View(model);
        }

        // at this stage we know that the model passed UI validation
        // so let's hand it to the service layer by constructing a
        // business model
        string error;
        if (!_service.TryProcessFile(model.File.InputStream, out error))
        {
            // there was an error while processing the file =>
            // redisplay the view and inform the user
            ModelState.AddModelError("file", error);
            return View(model);
        }

        return Content("thanks for submitting", "text/plain");
    }
}

最後のビットはサービス層です。これには 2 つの依存関係があります。1 つ目は入力ストリームを解析して のリストを返すことを処理Productし、2 つ目はそれらの製品をデータベースに永続化することを処理します。

ちょうどこのような:

public class ProductsService: IProductsService
{
    private readonly IProductsParser _productsParser;
    private readonly IProductsRepository _productsRepository;
    public ProductsService(IProductsParser productsParser, IProductsRepository productsRepository)
    {
        _productsParser = productsParser;
        _productsRepository = productsRepository;
    }

    public bool TryProcessFile(Stream input, out string error)
    {
        error = "";
        try
        {
            // Parse the Excel file to extract products
            IEnumerable<Product> products = _productsParser.Parse(input);

            // TODO: Here you may validate whether the products that were
            // extracted from the Excel file correspond to your business
            // requirements and return false if not

            // At this stage we have validated the products => let's persist them
            _productsRepository.Save(products);
            return true;
        }
        catch (Exception ex)
        {
            error = ex.Message;
        }
        return false;
    }
}

もちろん、これらの依存関係の 2 つの実装があります。

public class ExcelProductsParser: IProductsParser
{
    public IEnumerable<Product> Parse(Stream input)
    {
        // parse the Excel file and return a list of products
        // that you might have extracted from it
        ...
    }
}

およびリポジトリ:

public class Linq2SqlProductsRepository: IProductsRepository
{
    public void Save(IEnumerable<Product> products)
    {
        // save the products to the database
        ...
    }
}

注: このファイルのアップロードに関連付けることができ、フォームに対応する入力フィールドがいくつかあるメタデータを表す追加のプロパティを使用して、ビュー モデルを強化することができます。TryProcessFile次に、単純な の代わりにメソッドに渡すビジネス モデルを定義できますStream。この場合、コントローラ アクションでAutoMapperUploadViewModelを使用して、定義する とこの新しいビジネス モデルをマッピングできます。

于 2011-07-16T08:19:54.810 に答える