asp.net core 2从通过hangfire任务访问的作用域DI服务访问httpcontext

时间:2017-10-03 02:23:06

标签: asp.net-core hangfire

我有一个带有hangfire的asp.net core2应用程序。配置适用于基本任务,但是现在我需要排队后台作业,它访问依赖注入的httpcontext和dbcontext,我得到httpcontext的空引用异常 - 我理解为什么会这样,但是......

我是否可以配置hangfire的入队,以便作业中包含触发任务的httpcontext和dbcontext?作业总是最初从上下文可用的控制器中触发。该作业是ApprovalService上的一个方法,它将_userservice注入其构造函数中。 _Userservice在其构造函数中注入了httpContext。

据我所知,图表应该可以解决这个问题,这只是一个问题......

我不想重构将这些作为参数传递,因为服务在别处可以访问上下文的地方使用。

我的启动如下(为清晰起见,删除了很多内容)

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }
    private IHostingEnvironment _env;
    public static string connection;

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors();
        services.AddMvc(config => {
            config.Filters.Add(new AuthorizeFilter(authorizePolicy));
            config.OutputFormatters.OfType<StringOutputFormatter>().Single().SupportedMediaTypes.Add("text/html");
        })                
            .AddJsonOptions(options =>
                {
                    options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
                    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                });

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        connection = Configuration.GetConnectionString("(default)");

        services.AddDbContext<CpContext>(options =>
        {
            options.UseSqlServer(connection);
        });

        services.AddHangfire(configuration => configuration
            .UseSqlServerStorage(connection));

        services.AddScoped<IApprovalService, ApprovalService>();
        services.AddScoped<IUserService, UserService>();
        services.AddScoped<SystemControlService>();
        services.AddScoped<ProjectControlService>();
        services.AddIdentity<CpIdentityUser, IdentityRole>().AddUserManager<cpUserManager>();

        services.AddScoped<ApprovalService>();
        services.AddTransient<IEmailService, EmailService>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        Log.Information("In configure");
        _env = env;
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            //app.UseBrowserLink();
        }

        app.UseCors(x => x
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());

        app.UseAuthentication();

        app.UseMvc();
        app.UseStaticFiles();

        app.UseHangfireDashboard("/hangfire", new DashboardOptions
        {
            Authorization = new[] { new CustomAuthorizeFilter() }
        });
        app.UseHangfireServer();
    }

    public class CustomAuthorizeFilter : IDashboardAuthorizationFilter
    {
        public bool Authorize([NotNull] DashboardContext context)
        {
            var httpcontext = context.GetHttpContext();
            return httpcontext.User.Identity.IsAuthenticated;
        }
    }
}

我像这样解雇这个工作(非工作版本注释并且工作 - 当试图从上下文中获取userID时,hangfire工作挂起null引用);

[Produces("application/json")]
[Route("api/Approvals")]
public class ApprovalsController : Controller
{
    private readonly CpContext _context;
    private IUserService _userService;
    private IBackgroundJobClient _backgroundJobClient;
    private ApprovalService _approvalService;

    public ApprovalsController(CpContext context, IUserService userService, ApprovalService approvalService, IBackgroundJobClient backgroundJobClient)
    {
        _context = context;
        _userService = userService;
        _approvalService = approvalService;
        _backgroundJobClient = backgroundJobClient;
    }

    public class approvalWrapper
    {
        public int ApprovalId { get; set; }
        public List<string> emailTo { get; set; }
        public List<string> ccTo { get; set; }
        public string ManualApprCode { get; set; }
        public int RequestToId { get; set; }
        public DateTime RequestDate { get; set; }
        public DateTime RequiredDate { get; set; }
        public DateTime ResponseDate { get; set; }
        public string RequestText { get; set; }
        public string ResponseText { get; set; }
        public int ApprovalStatusTypeId { get; set; }
        public int ApprovalItemTypeId { get; set; }
        public int? NcrLinkId { get; set; }
        public int? LotItpDetailLinkId { get; set; }
        public int? LotQtyLinkId { get; set; }
    }

    // POST: api/Approvals/sendRequest
    [HttpPost("sendRequest")]
    public async Task<IActionResult> sendRequest([FromBody] approvalWrapper approvalInfo)
    {
        if (!ModelState.IsValid) return BadRequest(ModelState);
        Approval approval = new Approval()
        {
            RequestById = _userService.User_ID,
            RequestToId = approvalInfo.RequestToId,
            RequestDate = approvalInfo.RequestDate,
            RequiredDate = approvalInfo.RequiredDate,
            RequestText = approvalInfo.RequestText,
            NcrLinkId = approvalInfo.NcrLinkId,
            LotItpDetailLinkId = approvalInfo.LotItpDetailLinkId,
            LotQtyLinkId = approvalInfo.LotQtyLinkId,
            ApprovalItemTypeId = approvalInfo.ApprovalItemTypeId,
            ApprovalStatusTypeId = 5,
        };
        try
        {
            _context.Approval.Add(approval);
            await _context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            Log.Error(ex, "Error trying to create approval.");
            return StatusCode(422);
        }
        _backgroundJobClient.Enqueue<IApprovalService>(serv => serv.sendRequestEmailAsync(approval.ApprovalId, approvalInfo.emailTo, approvalInfo.ccTo));

        //await _approvalService.sendRequestEmailAsync(approval.ApprovalId, approvalInfo.emailTo, approvalInfo.ccTo);
        return Ok(1);
    }
}

interface IApprovalService
{
    Task<string> getApprovalRequestTextForChecklistItem(int checklistItemId);
    Task<string> getApprovalRequestTextForNCR(int NCRId);
    Task<bool> sendRequestEmailAsync(int apprToRequestID, List<string> emailTo = null, List<string> ccTo = null);
    Task<bool> sendResponseEmailAsync(int apprToRequestID, List<string> emailTo = null, List<string> ccTo = null);
    Task<bool> isApprovalCodeValidAsync(string qryString, int apprToRequestID);
}

public class ApprovalService: IApprovalService
{
    CpContext _context;
    IEmailService _emailService;
    private ProjectControlService _projectControlService;
    private SystemControlService _systemControlService;
    private IUserService _userService;

    public ApprovalService(CpContext context, IEmailService emailService, SystemControlService systemControlService,
        ProjectControlService projectControlService, IUserService userService)
    {
        _context = context;
        _emailService = emailService;
        _userService = userService;
        _systemControlService = systemControlService;
        _projectControlService = projectControlService;
    }

public interface IUserService
{
    int Project_ID { get; }
    int User_ID { get; }

    Task<UserCredDto> AuthenticateAsync(string username, string password);
    HashSet<string> getUserPermsForProject(int userID, int ProjectID);
    IEnumerable<User> GetAll();
    Task<User> GetByIdAsync(int id);
    Task<User> GetUserAsync();
    Task<User> CreateUserAsync(User user, string password);
    Task UpdateAsync(User user, string password = null);
    Task<User> DeleteAsync(int id);
    bool Exists(int id);
    string checkRefreshToken(string refreshToken, UserCredDto tokenOwner, int refreshLifeTime);
    Task<string> getNewRefreshTokenAsync(UserCredDto tokenOwner, int refreshLifeTime = 60);
    string GetUserName();
    Task<UserDto> GetUser();
    ClaimsPrincipal GetClaimsPrincipal();
}

public class UserService : IUserService
{
    private CpContext _context;
    private readonly IHttpContextAccessor _httpcontext;


    public UserService(CpContext context, IHttpContextAccessor httpcontext)
    {
        _context = context;
        _httpcontext = httpcontext;
    }
}

0 个答案:

没有答案