如何从多个地方使用MVC控制器

时间:2013-11-25 20:57:18

标签: c# asp.net-mvc asp.net-mvc-5

我正在构建一个MVC 5应用程序,用于处理员工的日志记录时间等。我已经拥有一个完整的CRUD控制器,其中包含处理员工记录的视图,我有一个时间表控制器,用于为员工输入时间。

我想在Timesheets / Index视图中添加快捷方式,以便无需通过Admin / Index视图即可访问Employees模块。我还想直接从下级视图访问Employee Edit方法到Timesheets / Index。

本着DRY的精神,我可以重用Employee控制器逻辑并仍然可以回到我来自的地方,或者我是否需要复制Employee逻辑以使用不同的操作链接调用不同的视图? (我知道我可以通过使用部分模板来重用部分视图代码,但这还远远不够。)

好的回答我没有很好地解释我想做什么。以下是Employees控制器代码的一部分:

public partial class EmployeesController : Controller
{
    //
    // GET: /Employees/

    public virtual ActionResult Index(int? page)
    {
        const int pageSize = 15;

        var masterDataProxy = MasterDataChannelFactory.OpenChannel();
        var employees = masterDataProxy.GetPagedEmployees((page ?? 0) * pageSize, pageSize);
        masterDataProxy.CloseChannel();

        ViewBag.HasPrevious = employees.HasPrevious;
        ViewBag.HasMore = employees.HasNext;
        ViewBag.CurrentPage = (page ?? 0);

        return View(employees.Entities);
    }

    //
    // GET: Employees/Edit/{id}

    //[Authorize(Roles = "Admin")]
    public virtual ActionResult Edit(int id)
    {
        var masterDataProxy = MasterDataChannelFactory.OpenChannel();
        var employee = masterDataProxy.GetEmployee(id);
        masterDataProxy.CloseChannel();

        return View(employee);
    }

    //
    // POST: Employees/Edit/{id}

    [AcceptVerbs(HttpVerbs.Post), /*Authorize(Roles = "Admin")*/]
    public virtual ActionResult Edit(int id, FormCollection formValues)
    {
        var masterDataProxy = MasterDataChannelFactory.OpenChannel();
        var employee = masterDataProxy.GetEmployee(id);
        masterDataProxy.CloseChannel();

        if (null == employee)
        {
            return View(Views.NotFound);
        }

        try
        {
            UpdateModel(employee, formValues.ToValueProvider());

            var adminProxy = AdminChannelFactory.OpenChannel();
            adminProxy.AddUpdateEmployee(employee);
            adminProxy.CloseChannel();

            return RedirectToAction(Actions.Index());
        }
        catch (Exception ex)
        {
            ModelState.AddModelError("Employee", ex.Message);

            return View(employee);
        }
    }
...
}

以下是管理员索引页面视图的一部分:

@{
    ViewBag.Title = "Master Data Admin";
}

<h2>Master Data</h2>

<ul>
    <li>@Html.ActionLink("Accounts", MVC.Account.Actions.Index())</li>
    <li>@Html.ActionLink("Employees", MVC.Employees.Actions.Index())</li>
</ul>

然后我有一个时间表/索引视图,我想在其中添加另一个ActionLink给员工。我的问题是如何编写这个,以便我可以从任何一个视图(Admin / Index或Timesheets / Index)调用Employees Controller,更新服务上的Employees,然后返回到我的调用地点?

这似乎应该是一个已解决的问题,但我找不到任何接近我想做的事情。也许我需要重新解释一下这个问题?我想补充一点,我是MVC和网络编程的新手......

提前感谢您的任何帮助或指导。

戴夫

3 个答案:

答案 0 :(得分:2)

如果我理解正确,您希望使用Employee操作方法,而不必与Employee视图绑定。

我会在您的应用程序中创建一个服务层(可能在一个单独的项目中)来处理Employee逻辑。然后,从您的Employee控制器和Timesheets控制器中调用此EmployeeService服务。

这样,您的业务逻辑(EmployeeService)就会与您的表示逻辑(EmployeeTimesheets控制器及相关视图分开)。因此,您的控制器可以使用存储在EmployeeService中的逻辑,并仍然使用自己的视图进行演示。

这实际上变成了一个双层设计。如果您的应用程序足够复杂,您甚至可以将数据访问逻辑分离到单独的层中 - 从而有效地使您的应用程序成为3层。

示例结构可能如下所示。

    Presentation Layer Project (PL)
        Controllers/
            EmployeeController
            TimesheetsController
        Views/
            Employee/
            Timesheets/
        ...

    Business Logic Layer Project (BLL)
        ViewModels/
        Services/
        ...

    Data Access Layer Project (DAL)
        Models/
        Repositories/
        ...

(这里PL将引用BLL,BLL将引用DAL项目)。

这可能会提供更多信息:https://softwareengineering.stackexchange.com/questions/135724/separating-data-access-in-asp-net-mvc

答案 1 :(得分:0)

所有这些都很棒,但我认为我所要求的是如此简单,它只是假设我已经知道了。我绝对可以看到存储库和业务层的优势,并且会做出正确的事情。并将数据访问分离出控制器。但是,这并没有回答我的问题。

我需要做的是获取编辑屏幕的内容并创建局部视图。然后我需要为每个控制器调用创建一个单独的视图,其中包含使我回到我开始的位置的正确链接。

从管理员/员工/编辑调用的视图:

@model HawkTimeModel.Employee

@{
    ViewBag.Title = "Edit Employee";
}

<h2>Edit</h2>

@{ Html.RenderPartial(MVC.Employees.Views._EmployeeForm); }

<p>
    @Html.ActionLink("Back to List", MVC.Employees.Actions.Index())
</p>

从Timesheet / EditEmployee查看:

@model HawkTimeModel.Employee

@{
    ViewBag.Title = "Edit Employee";
}

<h2>Edit</h2>

@{ Html.RenderPartial(MVC.Employees.Views._EmployeeForm); }

<p>
    @Html.ActionLink("Back to Timesheet Overview", MVC.Timesheets.Actions.Index())
</p>

那就是&#34;缺失的链接&#34;。现在看,我不明白我是如何忽视这么简单的事情。

感谢您提供的意见,我的应用会因您的反馈而更好!

戴夫

答案 2 :(得分:0)

我的同事提出了另一种解决方案。修改模型,使其具有一个变量,用于定义调用视图的位置,并使用该变量确定页面底部的“返回链接”。然后主索引视图如下所示:

@using WebReporter.Models

@{ Html.RenderPartial(MVC.Employees.Views._IndexPartial); }

@if (Model.HomePage == HomePage.Timesheets)
{
    <p>
        @Html.ActionLink("Back to Timesheet Overview", MVC.TimeSheets.Index())
    </p>
}

......并且这样称呼:

    public virtual ActionResult Index(HomePage homePage, int? page)
    {
        return View(_masterDataService.GetPagedEmployees(homePage, page));
    }

我最初构建了Employee视图和控制器的第二个副本,但它似乎违反了DRY原则,所以我正在尝试这个。

我无法相信这很难解释。我不可能是唯一一个想要从多个地方重用整个Controller + Views的人,所以我一定不好解释它......

感谢您的建议,我的代码将更适合您的输入!