我有一个带有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;
}
}