【问题标题】:How to Call Api Controller from another Api Controller In Same Project如何从同一项目中的另一个 Api 控制器调用 Api 控制器
【发布时间】:2019-10-22 12:17:08
【问题描述】:

我有一个对象“ApplicantDetail”,其中包含申请人控制器中的对象列表,我想将发布请求发送到 Personaldetails Api On 以保存到数据库并获得回复

申请者控制器上的 API

    // POST: api/ApplicantDetail
    [HttpPost]
    [Route("~/api/ApplicantDetail")]
    public IActionResult Post([FromBody] Personaldetail ApplicantDetail)
    {

        Personaldetail personaldetail = new Personaldetail
        {
            Name = ApplicantDetail.Name,
            Cnic = ApplicantDetail.Cnic,
            Phone = ApplicantDetail.Phone
        };

        List<Address> addresses = new List<Address>();
        List<Employee> employees = new List<Employee>();
        List<Bank> banks = new List<Bank>();

        addresses.AddRange(ApplicantDetail.Address);
        employees.AddRange(ApplicantDetail.Employee);
        banks.AddRange(ApplicantDetail.Bank);

        var response = *//How to Call Personaldetail Post APi of PersonaldetailController Controller From Here and Get 
          response back//*

        return null;
    }

个人详细信息控制器上的 API

    // POST: api/Personaldetails
    [HttpPost]
    public async Task<IActionResult> PostPersonaldetail([FromBody] Personaldetail personaldetail)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        _context.Personaldetail.Add(personaldetail);
        await _context.SaveChangesAsync();

        return CreatedAtAction("GetPersonaldetail", new { id = personaldetail.ApplicantId }, personaldetail);
    }

【问题讨论】:

  • 最好在控制器和业务逻辑之间创建隔离。当您这样做时,您可以轻松地重用业务方法并享受良好的分离。

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


【解决方案1】:

您应该创建一个服务类来表示个人详细信息 API。在此类中,您将注入 HttpClient,然后使用强类型客户端设置 IHttpClientFactory

public class PersonalDetailsService
{
    private readonly HttpClient _client;

    public PersonalDetailsService(HttpClient client)
    {
        _client = client;
    }

    // methods here to interact with API via `_client`
}

然后,在ConfigureServices

services.AddHttpClient<PersonalDetailsService>(c =>
{
    c.BaseAddress = new Uri(Configuration["PersonalDetailsAPIUrl"]);
    // configure anything else you need to on the `HttpClient`
});

最后,在你的控制器中,注入PersonalDetailsService

[ApiController]
[Route("api/ApplicantDetail")]
public class ApplicantController
{
    private readonly PersonalDetailsService _personalDetailsService;

    public ApplicantController(PersonalDetailsService personalDetailsService)
    {
        _personalDetailsService = personalDetailsService;
    }

    [HttpPost("")]
    public async Task<IActionResult> Post([FromBody] Personaldetail ApplicantDetail)
    {
        ...

        var response = await _personalDetailsService.SomeMethodAsync(someParam);

        return null;
    }
}

【讨论】:

  • 为什么我不能直接从另一个api控制器B调用controllerA的api ....?
  • 因为这不是它的工作原理。控制器不仅仅是类。它们依赖于请求管道,除非您通过请求“调用”它们,否则事情不会按应有的方式工作。您可以尝试以各种骇人听闻的方式进行补偿,但这只会使您的代码更脆弱且更难维护。此外,它们必须存在于同一个项目中,即使它们现在存在,它们也可能并不总是存在。您不想将自己锁定在特定的设计中。
  • 最后,即使他们将生活在同一个项目中,正确的方法是将您需要共享的逻辑分解到某种帮助类中,然后两者控制器可以使用,而不是从另一个控制器调用一个控制器操作。
  • @ChrisPratt -- 你解释得非常好。当我被问到这个问题时,我通常只是沉重地。
【解决方案2】:

如果这是在同一个进程中,从另一个控制器调用一个控制器是不明智的。

创建一个类(通常称为服务)更为常见,您可以在其中放置应用手头任务的逻辑。

这会有一些好处:

  • 逻辑隔离
  • 更换一个端点时不必担心
  • 不用担心更改网址或身份验证
  • 没有不必要的网络操作

例如:

服务:

public class YourService
{
    public void YourMethod(parameters)
    {
       //do your stuff
    }
}

用法:

public class Controller1 : Controller
{
    public void YourAction1()
    {
        //controller specific stuff like model validation      

        //shared logic
        var service = new YourService();
        service.YourMethod();
    }
}

public class Controller2 : Controller
{
    public void YourAction2()
    {
        //controller specific stuff like model validation      

        //shared logic
        var service = new YourService();
        service.YourMethod();
    }
}

您也可以使用 DI 框架来解决您的服务。

【讨论】:

    【解决方案3】:

    我可以看到你在 controller2(Personaldetail Controller)上的目标方法(PostPersonaldetail)是一个异步方法。当我们调用它时,我们需要使用 await 关键字并将 async 应用于方法(POST:api/ApplicantDetail),因为我们不能使用 await 关键字,而不将方法设置为 async。或者,我们也可以在方法调用上应用 wait

    控制器只是类,我们可以创建一个实例并调用其中定义的方法,但这不是一个好习惯。使用依赖注入,我们可以在应用程序中获取对其他服务/控制器的引用,并使用它来调用在它们上定义的方法。

    方法一:

     public async IActionResult Post([FromBody] Personaldetail ApplicantDetail)
     {
        var response = await new controller2().PostPersonaldetail(persondetails);
     }
    

    方法二:

     public IActionResult Post([FromBody] Personaldetail ApplicantDetail)
     {
        var response = new controller2().PostPersonaldetail(persondetails).Wait();
     }
    

    以下链接可能会有所帮助。

    Resource 1

    Resource 2

    【讨论】:

    • 感谢您的帮助。它对我不起作用,但我发现你的描述对我有帮助。
    • 我同意这是一种粗鲁的方式,我们永远不应该从一个控制器调用另一个控制器。我偶然发现了这个问题,因为一些聪明的面试官问我如何在控制器之间调用一个动作。
    【解决方案4】:

    我认为您不想新建一个实例,因为它可能缺少依赖项。您可以执行以下操作:

    var controller = DependencyResolver.Current.GetService<PostPersonaldetail>();
    controller.ControllerContext = new ControllerContext(this.Request.RequestContext, controller);
    

    然后拨打电话。

    你也可以使用依赖注入,只在控制器中有一个引用:

    class ApplicantController : ControllerBase
    {
        public ApplicantController(ControllerB controllerb)
        {
            _contollerB = controllerB;
        }
    

    您可能需要添加一个调用来添加临时服务:

    services.AddTransient<ControllerB>();
    

    【讨论】:

      猜你喜欢
      • 2017-10-14
      • 1970-01-01
      • 2017-03-01
      • 1970-01-01
      • 2015-08-24
      • 1970-01-01
      • 2015-09-07
      • 2013-10-10
      相关资源
      最近更新 更多