2011-11-17 33 views
2

我有一个现有的ASP.NET MVC的网站,像这样的动作:大厦的API在ASP.NET MVC网站

public ActionResult Show(int id) 
{ 
    var customer = GetCustomer(id); 

    return View(new ShowCustomerModel(customer)); 
} 

我现在需要执行这些操作的API的一部分的能力,这将是从第三方应用程序调用。理想情况下,动作看起来像:

public ActionResult Get(int id) 
{ 
    var customer = GetCustomer(id); 

    return Json(new CustomerResource(customer)); 
} 

的问题是,什么ASP.NET MVC的工具或模式存在,让我将这些结合在一起 - 比如,Rails允许我指定多个返回格式:

def index 
  @customer = get_customer(...) 

  respond_to do |format| 
    format.html # index.html.erb 
    format.xml  { render :xml => @customer} 
   format.json { render :json => @customer} 
  end 
end 

这是一个很好的模式吗?我应该也许只是有:

public Customer Get(int id) 
{ 
    return GetCustomer(id); 
} 

并使用操作筛选器选择性呈现为JSON或视图?

回答

8

我想创建一个ActionResult可以足够聪明,以确定您在此基础上提供,像这样的接受头想要什么样的结果:

public class AdaptiveActionResult : ActionResult 
{ 
    private readonly object _model; 

    public AdaptiveActionResult(object model) 
    { 
     _model = model; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     var accept = context.HttpContext.Request.AcceptTypes; 
     if (accept == null || !accept.Contains("application/json")) 
     { 
      var viewResult = new ViewResult {ViewData = new ViewDataDictionary(_model)}; 
      viewResult.ExecuteResult(context); 
      return; 
     } 

     var jsonResult = new JsonResult 
          { 
           Data = _model, 
           JsonRequestBehavior = JsonRequestBehavior.AllowGet 
          }; 
     jsonResult.ExecuteResult(context); 
     return; 
    } 
} 

这可以扩展以检查如果他们想要XML,RSS,Atom,什么都可以。

然后你就可以做到这一点在你的控制器像这样:

public ActionResult Index() 
    { 
     return new AdaptiveActionResult(new MyModel()); 
    } 
+0

这是一个非常酷的方法! –

3

它可能不是您想要的,但您可以检查请求类型并采取相应措施。

public ActionResult Get(int id) 
{ 
    if (Request.IsAjaxRequest) 
    { 
     // do stuff 
     return new JsonResult(new { Foo = "Foo", Bar = "Bar" }); 
    } 
    else 
    { 
     // do stuff 
     return View(myModel); 
    } 

    // if you need beyond IsAjaxRequest, you could 
    // check the controller's Request object for other 
    // indicators as to what type of result to 
    // send back 
} 
1

您可以为每一个3个行动和创建一个自定义属性,并创建一个ActionInvoker只是喜欢的方式HttpPost和HTTPGET工作

[JsonRequest] 
[ActionName("Get")] 
public ActionResult GetAsJson(int id) { 
    //return as Json 
} 

[XmlRequest] 
[ActionName("Get")] 
public ActionResult GetAsXml(int id) { 
    //return as xml 
} 

public ActionResult Get(int id) { 
    //get stuff normally 
} 

这显然需要编码,以获得工作的一个位,但将可重复使用。

另一种方法是创建一个CustomerResult对象,只是有一个动作,做丹尼尔上面提到的,但这个逻辑可以放入您CustomerResult对象。

6

你可以建立一个自定义操作过滤器属性赶内容类型的操作执行时并存储到一个参数:

public class ContentTypeRequestFilter : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     filterContext.ActionParameters["contentType"] = 
      filterContext.HttpContext.Request.ContentType; 
     base.OnActionExecuting(filterContext); 
    } 
} 

然后在你的控制器,你可以装饰你的操作方法,添加参数,并做一个检查:

[ContentTypeRequestFilter] 
public ActionResult Get(int id, string contentType) 
{ 
    var customer = GetCustomer(id); 
    if(contentType.ToLower() == "application/json") 
    { 
     return Json(new CustomerResource(customer)); 
    } 
    return View(new ShowCustomerModel(customer)); 
} 

从那里你可以适应其他内容请求类型(XML等),如果需要。我在Building a REST API architecture in MVC 3上的博客文章中采取了类似的方法。

+0

+1请求过滤器是去这里的最佳方式。 –

3

@Schwarty's answer是最好的,如果你想你的网站内坚持并执行AUTOMAGIC红宝石的事情。

但我建议你建立一个单独的前端的API。主要问题是版本控制 - 你真的不应该发布不可版本化的api。我们人类阅读网页可以很容易地适应更新的数据模型。也许不容易,但是当事情发生变化时我们通常不会中断。然而,您的API的消费者是经常与您的特定实现绑定并且不喜欢更改的机器。

简短版本:它们是单独的任务,应在大多数情况下单独处理。

+0

我同意API的一个单独的接口点将是一个好方法。您可以在您的MVC应用程序中为您的API创建一个新的区域,并且仍然在站点和API中使用相同的数据和业务逻辑。 –

+0

或者只是引用相同核心程序集的另一个项目。 。 。 –

+0

这实际上就是我最终做的 - 一个提供JSON的WCF WebApi服务的a/api路由。 –