【问题标题】:call another api controller调用另一个 api 控制器
【发布时间】:2014-02-01 01:49:48
【问题描述】:

当我调用用户控制器 (api/user) 时,我能够传递用户凭据,但是应用程序崩溃并在值控制器中出现 null 异常错误(Value cannot be null):

   public class ValuesController : ApiController
   {
   private cdwEntities db = new cdwEntities();

   public HttpResponseMessage Get([FromUri] Query query)
   {
       var data = db.database.AsQueryable();

       if (query.name != null)
       {
           data = data.Where(c => c.Name == query.name);
       }

       if (query.price != null)
       {
           data = data.Where(c => c.Price == query.price);
       }


       if (!data.Any())
       {
           var message = string.Format("error");
           return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
       }

       ***return Request.CreateResponse(HttpStatusCode.OK, data);***
   }

}

我相信这个错误是因为 valuescontroller 方法不能传递空值,因为它总是传递参数(即 api/values/name=tom),因此当我调用用户控制器时,它会抛出 null 错误,因为系统没有传递任何参数从用户控制器进入 Valuescontroller。

public class UserController : ApiController
{
    [Authorize]
    public HttpResponseMessage Get([FromUri] Query query)
    {
        if (User.IsInRole("user"))
        {
            var result = new itemController();
            return result.Get(query);
        }

        var message = string.Format("No data was found");
        return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
    }

}

它们是我可以用来解决这个问题的一些内置函数还是我应该研究的任何框架/库? 非常感谢您的帮助和时间。

【问题讨论】:

  • 不要那样做。相反,将公共代码提取到可重用的单独函数中。
  • 我同意@SLaks。您应该使用具有该逻辑的通用服务类..
  • 感谢您的回复。澄清一下,您是否建议我应该在值控制器中执行此任务。我有两个 API 控制器,我希望能够将特定用户定向到这些 api 控制器。任何人都可以提供任何指南/框架,我该如何完成这项任务。
  • 嗯太糟糕了,我有一个 GetMethod 应该移动到其他控制器。但我想通过GetMethod() {return _otherController.GetMethod();} 保持向后兼容性

标签: c# asp.net-mvc asp.net-web-api


【解决方案1】:

其他人指出,您不应该经常(曾经?)从另一个视图控制器端点调用一个视图控制器端点,但是在您需要/想要的情况下,您需要确保目标已正确初始化。这是使用ControllerBuilder 完成的。

所以而不是:

var result = new itemController();
return result.Get(query); // this will blow up!

你会这样做:

IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
itemController c = (itemController) factory.CreateController(
    ControllerContext.RequestContext, "item");
return c.Get(query);

这将确保目标视图控制器已使用所有必要的上下文进行初始化。

【讨论】:

    【解决方案2】:

    您不应从其他 API 端点调用一个 API 端点方法。相反,您需要在 API、业务逻辑层和数据访问层之间进行适当的代码隔离。我会按照以下方式进行 -

    API -

        public class UserController : ApiController
        {
            [Authorize]
            public HttpResponseMessage Get([FromUri] Query query)
            {
                BusinessLayer layer = new BusinessLayer();
                if (User.IsInRole("user"))
                {
                    var result = layer.GetData(query);
                    // use result here and return HttpResponseMessage
                    var message = string.Format("No data was found");
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
                }
            }
        }
    

    在你的业务逻辑层——

       public ResultModel Get(Query query)
       {
           // Process your model Query here... and then return some meaningful result here...
           // Also call Data Access Layer Methods from here, instead of making direct database
           // (entity framework) calls...
       }
    

    为了更好的灵活和松耦合的系统,你需要有Dependency Injection (probably using Unity, but there are many other options like Autofac, Ninject etc.)

    【讨论】:

    • 非常感谢您的反馈和帮助。这是否类似于在业务逻辑层中使用存储库。请原谅我的知识是 web api 的新功能并且仍在学习。
    • 是的,你是对的。这是存储库模式,我建议你。
    猜你喜欢
    • 2017-10-14
    • 2017-03-01
    • 2015-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多