Linq to sql ASP.NET MVC-多层结构

Linq to sql ASP.NET MVC-多层结构,linq-to-sql,asp.net-mvc-2,business-logic,multi-layer,Linq To Sql,Asp.net Mvc 2,Business Logic,Multi Layer,我一直在使用LinqToSql进行ASP.NETMVC项目。该应用程序有3层:UI、业务和数据 在过去的几天里,我实现了(我现在仍然是)一个Excel文件上传。因此,我的控制器接收上传的文件,做一些事情,将信息传递给企业,然后传递给数据。但是,随着这一趋势的发展,出现了一些疑问 以下是我的一些疑问(我认为子弹是最简单的表达方式): 必须验证Excel文件。应用程序必须验证工作表值是否正确,如果正确,则插入/更新数据库。我应该在Controller中还是在业务中验证Excel 此Excel可能会将

我一直在使用LinqToSql进行ASP.NETMVC项目。该应用程序有3层:UI、业务和数据

在过去的几天里,我实现了(我现在仍然是)一个Excel文件上传。因此,我的控制器接收上传的文件,做一些事情,将信息传递给企业,然后传递给数据。但是,随着这一趋势的发展,出现了一些疑问

以下是我的一些疑问(我认为子弹是最简单的表达方式):

  • 必须验证Excel文件。应用程序必须验证工作表值是否正确,如果正确,则插入/更新数据库。我应该在Controller中还是在业务中验证Excel

  • 此Excel可能会将数据插入数据库,例如,
    新产品()在UI层中创建新实例时有问题吗?还是在业务中创建新实例更好?将一个对象从UI传递到业务是更好的选择,还是传递所有类属性并在业务中创建该对象更好

  • 在这个Excel操作中,我使用了一些辅助方法,比如验证工作表是否已结束、验证单元格是否有值、为上载的文件生成DataTable以及其他一些方法。这些助手方法应该放在哪里?目前,它们位于UI层(与控制器相同)

  • 忘记Excel,想象一下一个简单的产品表单页面。在POST上,控制器将收到FormCollection。这个表单集合应该在控制器上处理,还是应该传递给业务部门,由业务部门完成所有工作

  • 对不起,有很多问题。我还试图重构我的代码,“胖控制器”的问题就在我的门上


    提前谢谢

    你确实应该避免使用脂肪控制器。但总是说起来容易做起来难

    让我试着用一个例子来回答你们的问题。与往常一样,您可以从设计一个视图模型开始,该模型将表示用户发送到此操作的数据(不要使用任何弱类型的
    FormCollection
    ViewData

    然后我们转到控制器:

    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");
        }
    }
    
    最后一位是服务层。它将有两个依赖项:第一个将负责解析输入流并返回
    产品的列表,第二个将负责将这些产品持久化到数据库

    就这样,

    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;
        }
    }
    
    公共类产品服务:IPProductsService
    {
    私有只读IPProductsParser\u productsParser;
    私有只读IPProductsRepository\u productsRepository;
    公共产品服务(IPProductsParser产品sParser、IPProductsRepository产品Repository)
    {
    _productsParser=productsParser;
    _productsRepository=productsRepository;
    }
    公共bool进程文件(流输入,输出字符串错误)
    {
    错误=”;
    尝试
    {
    //解析Excel文件以提取产品
    IEnumerable products=\u productsParser.Parse(输入);
    //TODO:在这里,您可以验证
    //从Excel文件中提取,与您的业务相对应
    //要求,否则返回false
    //在这个阶段,我们已经验证了产品=>让我们将其持久化
    _产品存储。保存(产品);
    返回true;
    }
    捕获(例外情况除外)
    {
    错误=例如消息;
    }
    返回false;
    }
    }
    
    当然,这些依赖关系有两种实现:

    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
            ...
        }
    }
    
    公共类ExcelProductSpaser:IPProductSpaser
    {
    公共IEnumerable解析(流输入)
    {
    //解析Excel文件并返回产品列表
    //你可能从中提取的
    ...
    }
    }
    
    以及存储库:

    public class Linq2SqlProductsRepository: IProductsRepository
    {
        public void Save(IEnumerable<Product> products)
        {
            // save the products to the database
            ...
        }
    }
    
    公共类Linq2SqlProductsRepository:IProductsRepository
    {
    公共作废保存(IEnumerable产品)
    {
    //将产品保存到数据库中
    ...
    }
    }
    

    备注:您可以使用其他属性丰富视图模型,这些属性将表示一些元数据,我们可以将这些元数据与此文件上载关联,并且表单上可能有一些相应的输入字段。然后您可以定义一个要传递给
    TryProcessFile
    方法的业务模型,而不是一个简单的
    。在这种情况下,可以在控制器操作中使用来映射
    UploadViewModel
    和您将定义的新业务模型。

    Darin,谢谢您的评论!它帮助我建立了一些关于重构代码的坚实思想!
    public class Linq2SqlProductsRepository: IProductsRepository
    {
        public void Save(IEnumerable<Product> products)
        {
            // save the products to the database
            ...
        }
    }