gpt4 book ai didi

asp.net - 多个 Controller 、一个 View 和一个模型 ASP.NET MVC 3

转载 作者:行者123 更新时间:2023-12-02 16:56:07 33 4
gpt4 key购买 nike

我想在我的 ASP.NET MVC 3 应用程序中拥有一个由多个 Controller 提供服务的模型和 View 。

我正在实现一个与用户的在线日历交互的系统,并且我支持 Exchange、Google、Hotmail、Yahoo、Apple 等……它们中的每一个都有完全不同的日历 API 实现,但我可以用我的自己的模型。我认为通过在 Controller 级别实现多态性,我将能够干净地处理不同的 API 和身份验证问题。

我有一个很好的干净模型和 View ,到目前为止我已经实现了两个 Controller ,证明我可以读取/查询/写入/更新到 Exchange 和 Google: ExchangeController.csGoogleController.cs

我有 /Views/Calendar 包含我的 View 代码。我也有 /Models/CalendarModel.cs 包括我的模型。

我希望在我的 ControllerFactory 中测试用户正在使用的日历系统。我已经这样实现了:

public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == typeof(CalendarController))
{
if(MvcApplication.IsExchange) // hack for now
return new ExchangeController();
else
return new GoogleController();
}
return base.GetControllerInstance(requestContext, controllerType);
}
}

在我的 Application_Start 中:
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());

这行得通。如果我到达 http://.../Calendar,这个工厂代码就可以工作并创建正确的 Controller !

这工作得很好,我在没有真正理解我在做什么的情况下做到了。现在我想我明白了,但我想确保我没有遗漏什么。我真的花时间寻找这样的东西,但没有找到任何东西。

我担心的一件事是,我认为我可以在 CalendarControllerExchangeController/ GoogleController 之间建立这样的继承关系:
public class ExchangeController : CalendarController
{

但如果我这样做,我会得到:
The current request for action 'Index' on controller type 'GoogleController' is ambiguous between the following action methods:
System.Web.Mvc.ViewResult Index(System.DateTime, System.DateTime) on type Controllers.GoogleController
System.Web.Mvc.ActionResult Index() on type Controllers.CalendarController

这让我很沮丧,因为我想在基础上添加一些通用功能,现在我想我将不得不使用另一种方式。

这是为一个 View /模型设置多个 Controller 的正确方法吗?我还要考虑什么?

编辑:有关我的 impl 的更多详细信息

根据下面的回复(谢谢!)我认为我需要显示更多代码以确保你们看到我正在尝试做的事情。我的模型实际上只是一个数据模型。它从这个开始:
/// <summary>
/// Represents a user's calendar across a date range.
/// </summary>
public class Calendar
{
private List<Appointment> appointments = null;

/// <summary>
/// Date of the start of the calendar.
/// </summary>
public DateTime StartDate { get; set; }

/// <summary>
/// Date of the end of the calendar
/// </summary>
public DateTime EndDate { get; set; }

/// <summary>
/// List of all appointments on the calendar
/// </summary>
public List<Appointment> Appointments
{
get
{
if (appointments == null)
appointments = new List<Appointment>();
return appointments;
}
set { }
}


}

然后我的 Controller 有以下方法:
public class ExchangeController : Controller
{
//
// GET: /Exchange/
public ViewResult Index(DateTime startDate, DateTime endDate)
{
// Exchange specific gunk. The MvcApplication._service thing is a temporary hack
CalendarFolder calendar = (CalendarFolder)Folder.Bind(MvcApplication._service, WellKnownFolderName.Calendar);

Models.Calendar cal = new Models.Calendar();
cal.StartDate = startDate;
cal.EndDate = endDate;

// Copy the data from the exchange object to the model
foreach (Microsoft.Exchange.WebServices.Data.Appointment exAppt in findResults.Items)
{
Microsoft.Exchange.WebServices.Data.Appointment a = Microsoft.Exchange.WebServices.Data.Appointment.Bind(MvcApplication._service, exAppt.Id);
Models.Appointment appt = new Models.Appointment();
appt.End = a.End;
appt.Id = a.Id.ToString();

...
}

return View(cal);
}

//
// GET: /Exchange/Details/5
public ViewResult Details(string id)
{
...
Models.Appointment appt = new Models.Appointment();
...
return View(appt);
}


//
// GET: /Exchange/Edit/5
public ActionResult Edit(string id)
{
return Details(id);
}

//
// POST: /Exchange/Edit/5
[HttpPost]
public ActionResult Edit(MileLogr.Models.Appointment appointment)
{
if (ModelState.IsValid)
{
Microsoft.Exchange.WebServices.Data.Appointment a = Microsoft.Exchange.WebServices.Data.Appointment.Bind(MvcApplication._service, new ItemId(appointment.Id));

// copy stuff from the model (appointment)
// to the service (a)
a.Subject = appointment.Subject

...
a.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToNone);

return RedirectToAction("Index");
}
return View(appointment);
}

//
// GET: /Exchange/Delete/5
public ActionResult Delete(string id)
{
return Details(id);
}

//
// POST: /Exchange/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(string id)
{
Microsoft.Exchange.WebServices.Data.Appointment a = Microsoft.Exchange.WebServices.Data.Appointment.Bind(MvcApplication._service, new ItemId(id));
a.Delete(DeleteMode.MoveToDeletedItems);
return RedirectToAction("Index");
}

所以它基本上是典型的 CRUD 东西。我提供了 ExchangeCalendar.cs 版本中的示例。 GoogleCalendar.cs 在实现上显然是相似的。

我的模型(日历)和相关类(例如约会)是从 Controller 传递到 View 的。我不希望我的 View 看到正在使用的底层在线服务的详细信息。我不明白如何用接口(interface)(或抽象基类)实现 Calendar 类会给我我正在寻找的多态性。

在某些地方,我必须根据用户选择要使用的实现。

我可以这样做:
  • 在我的模型中。我不想这样做,因为这样我的模型就会因服务特定的代码而变得很糟糕。
  • 在 Controller 中。例如。使用重定向到正确实现
  • 的内容启动每个 Controller 方法
  • 在 Controller 下方。例如。正如我在上面建议的那样,使用新的 Controller 工厂。

  • 下面的回复提到了“服务层”。我认为这也许是我偏离轨道的地方。如果您查看 MVC 与数据库正常完成的方式,dbContext 代表“服务层”,对吗?所以也许你们建议的是我可以做间接的第四个地方?例如上面的 Edit 会是这样的:
        private CalendarService svc = new CalendarService( e.g. Exchange or Google );

    //
    // POST: /Calendar/Edit/5
    [HttpPost]
    public ActionResult Edit(MileLogr.Models.Appointment appointment)
    {
    if (ModelState.IsValid)
    {
    svc.Update(appointment);
    return RedirectToAction("Index");
    }
    return View(appointment);
    }

    这是正确的方法吗?

    抱歉,这已经变得如此冗长,但这是我知道如何获得足够上下文的唯一方法......
    结束编辑

    最佳答案

    我不会这样做。正如 Jonas 指出的那样, Controller 应该非常简单,旨在协调用于响应请求的各种“服务”。请求流真的因日历而异吗?或者获取该数据所需的数据调用是否不同。

    做到这一点的一种方法是将日历分解为公共(public)日历接口(interface)(或抽象基类),然后通过构造函数参数将日历接受到 Controller 中。

    public interface ICalendar {
    // All your calendar methods
    }

    public abstract class Calendar {
    }

    public class GoogleCalendar : Calendar {}

    public class ExchangeCalendar : Calendar {}

    然后在您的 CalendarController 中,
    public class CalendarController {
    public CalendarController(ICalendar calendar) {}
    }

    这在默认情况下不起作用,除非您注册依赖解析器。一种快速的方法是使用 NuGet 安装一个安装包。例如:
    Install-Package Ninject.Mvc3

    我认为这将是一个更好的架构。但假设你不同意,让我回答你原来的问题。

    你得到这个模棱两可的异常(exception)的原因是你有两个公共(public) Index没有通过属性区分的方法,该属性指示一个应该响应 GET,一个响应 POST。 Controller 的所有公共(public)方法都是 Action 方法。

    如果 CalendarController不打算直接实例化(即它将始终被继承),那么我将在该类 protected virtual 上创建 Index 方法然后在派生类中覆盖它。

    如果 CalendarController意味着要自行实例化,而其他派生类只是它的“ flavor ”,那么您需要制作 Index方法 public virtual然后让每个派生类覆盖 Index方法。如果他们不覆盖它,他们将添加另一个 Index方法(C# 规则,不是我们的),并且为了 MVC 的缘故,您需要区分它们。

    关于asp.net - 多个 Controller 、一个 View 和一个模型 ASP.NET MVC 3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8288028/

    33 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com