将IHttpContextAcessor注入到Controller Action内的绑定模型中

时间:2016-10-31 08:06:41

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

我有一个控制器动作方法:

#include <Windows.h>
#include <Wininet.h>

#include <memory>

#pragma comment(lib, "Wininet.lib")

#include <iostream>

bool GetUrlCacheEntryInfo(const wchar_t* pUrl, std::unique_ptr<unsigned char[]>& pUrlCacheEntryInfo, DWORD nBufferSize = sizeof(INTERNET_CACHE_ENTRY_INFO))
{
    std::unique_ptr<unsigned char[]> pTemporaryUrlCacheEntryInfo(new unsigned char[nBufferSize]);
    if (GetUrlCacheEntryInfo(pUrl, reinterpret_cast<LPINTERNET_CACHE_ENTRY_INFO>(pTemporaryUrlCacheEntryInfo.get()), &nBufferSize) == FALSE)
    {
        const DWORD nError = GetLastError();
        if (nError == ERROR_INSUFFICIENT_BUFFER)
        {
            pTemporaryUrlCacheEntryInfo.reset(new unsigned char[nBufferSize]);
            if (GetUrlCacheEntryInfo(pUrl, reinterpret_cast<LPINTERNET_CACHE_ENTRY_INFO>(pTemporaryUrlCacheEntryInfo.get()), &nBufferSize) == FALSE)
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    pUrlCacheEntryInfo = std::move(pTemporaryUrlCacheEntryInfo);
    return true;
}

void PrintUrlCacheEntryInfo(LPINTERNET_CACHE_ENTRY_INFO pUrlCacheEntryInfo)
{
    std::cout << "Cache Entry Info:\n\tSize: " << pUrlCacheEntryInfo->dwStructSize << "\n\tUrl: ";
    std::wcout << pUrlCacheEntryInfo->lpszSourceUrlName;
    std::cout << "\n\tLocal File:";
    std::wcout << pUrlCacheEntryInfo->lpszLocalFileName;
    std::cout << "\n\tType: ";
    switch (pUrlCacheEntryInfo->CacheEntryType)
    {
    case EDITED_CACHE_ENTRY:
        std::cout << "EDITED_CACHE_ENTRY";
        break;
    case SPARSE_CACHE_ENTRY:
        std::cout << "SPARSE_CACHE_ENTRY";
        break;
    case STICKY_CACHE_ENTRY:
        std::cout << "STICKY_CACHE_ENTRY";
        break;
    case TRACK_OFFLINE_CACHE_ENTRY:
        std::cout << "TRACK_OFFLINE_CACHE_ENTRY";
        break;
    case TRACK_ONLINE_CACHE_ENTRY:
        std::cout << "TRACK_ONLINE_CACHE_ENTRY";
        break;
    default:
        std::cout << "UNKNOWN";
        break;
    }
    std::cout << "\n\tHeaders: ";
    std::wcout << pUrlCacheEntryInfo->lpHeaderInfo;
    std::cout << "\n";
}

int main(int argc, char** argv)
{
    const wchar_t* pUrl = L"https://h6.msn.com/library/8.8/dapmsn.js";
    std::unique_ptr<unsigned char[]> pUrlCacheEntryInfo;
    if (GetUrlCacheEntryInfo(pUrl, pUrlCacheEntryInfo))
    {
        PrintUrlCacheEntryInfo(reinterpret_cast<LPINTERNET_CACHE_ENTRY_INFO>(pUrlCacheEntryInfo.get()));
    }
    else
    {
        std::wcout << L"Cache entry for url " << pUrl << L" was  not found!\n";
    }
    return EXIT_SUCCESS;
}

我使用构造函数上课 RegisterTenantCommand

public void Register([FromBody]RegisterTenantCommand message)
{
    ...
}

但是当我启动我的应用并执行此操作时,我有 httpContextAccessor = null

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:4)

似乎您将命令与来自UI框架的命令混淆(如ICommand接口的WPF + MVVM实现)。

当前的实现也违反了SRP原则,其中一个类应该只负责一件事。您基本上处理输入(将其绑定到用户值)并执行它以及处理其中的执行逻辑。

命令/处理程序或CQRS模式中的命令仅仅是消息,它们只包含数据(可以或不可以序列化并通过消息总线发送以供其他后台进程处理)。

// ICommand is a marker interface, not to be confused with ICommand from WPF
public class RegisterTenantCommand : ICommand
{
    public string TenantId { get; set; }
    public string Name { get; set; }
}

命令处理程序包含一个标记接口及其实现(1:1关系,1个命令的1个处理程序)。

public interface ICommandHandler<T> where T : ICommand
{
    void Handle(T command);
}

public class RegisterTenantCommandHandler : ICommandHandler<RegisterTenantCommand>
{
    private readonly IHttpContext context;

    // You should really abstract this into a service/facade which hides
    // away the dependency on HttpContext
    public RegisterTenantCommandHandler(IHttpContextAccessor contextAccessor)
    {
        this.context = contextAccesspor.HttpContext;
    }

    public void Handle(RegisterTenantCommand command)
    {
        // Handle your command here
    }
}

在使用第三方IoC(如Autofac)时自动注册或使用内置IoC手动注册(此处我将使用内置):

services.AddTransient<ICommandHandler<RegisterTenantCommand>, RegisterTenantCommandHandler>();

您可以在动作或控制器或任何其他服务中注入它:

public class TenantController 
{
    public TenantController(ICommandHandler<RegisterTenantCommand> registerTenantHandler)
    {
        ...
    }
}

或行动

public Task<IActionResult> RegisterTenant(
    [FromBody]RegisterTenantCommand command,
    [FromService]ICommandHandler<RegisterTenantCommand> registerTenantHandler
)
{
    registerTenantHandler.Handle(command);
}

当然,您可以进一步抽象这一点,只注入一个将解析和处理所有命令的单个接口类,然后调用它generalCommandHandler.Handle(command),它的实现将解析并处理它。

答案 1 :(得分:0)

默认情况下不再注册IHttpContextAccessor服务

  

IHttpContextAccessor可用于访问HttpContext   当前线程。但是,保持这种状态并非易事   性能成本因此已从默认设置中删除   服务。

     

依赖它的开发人员可以根据需要添加它:
  services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

     

请参阅aspnet/Hosting#793进行讨论。

相关问题