当向调度程序添加作业时:Value不能为空,Job class不能为空?



我的问题非常类似:Quartz.net -";Job'’s key不能为null"然而,它的不同设置,因为我使用Rest API。当我通过Startup.cs添加时,我能够运行一个作业,但是当我调用API使用javascript添加作业时,它会失败,错误如下:

错误:

System.ArgumentNullException: Value cannot be null. (Parameter 'typeName')
at System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, StackCrawlMark& stackMark)
at System.Type.GetType(String typeName)
at Quartz.Web.Api.JobsController.AddJob(String schedulerName, String jobGroup, String jobName, String jobType, Boolean durable, Boolean requestsRecovery, Boolean replace) in E:AmitDotNetQuartzApiQuartzApiControllersJobsController.cs:line 108
at lambda_method14(Closure , Object )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

HEADERS
=======
Accept: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: close
Content-Length: 83
Content-Type: application/json
Host: localhost:44379
Referer: https://localhost:44379/jobs.html
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"
sec-ch-ua-mobile: ?0
origin: https://localhost:44379
sec-fetch-site: same-origin
sec-fetch-mode: cors
sec-fetch-dest: empty

设置:

在VS中,我在一个项目中创建了Quartz REST API和前端。运行这个项目会在后台加载带有job和API的网页。

所有控制器端点工作,除了AddJob。(即获取作业、查看作业详细信息、暂停、恢复、触发、删除)

依赖:Quartz.Extensions.Hosting 3.3.3

JobsController.cs石英网/JobsController.cs在main·quartznet/石英网·GitHub

[HttpPut]
[Route("{jobGroup}/{jobName}")]
public async Task AddJob(string schedulerName, string jobGroup, string jobName, string jobType, bool durable, bool requestsRecovery, bool replace = false)
{
var scheduler = await GetScheduler(schedulerName).ConfigureAwait(false);
var jobDetail = new JobDetailImpl(jobName, jobGroup, Type.GetType(jobType), durable, requestsRecovery);
await scheduler.AddJob(jobDetail, replace).ConfigureAwait(false);
}

HelloWorldJob.cs:https://andrewlock.net/using-quartz-net-with-asp-net-core-and-worker-services/

Startup.cs:(添加一个没有API的作业,并在开始时使用触发器运行它)

void ConfigureHostQuartz(IServiceCollection services)
{
services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionScopedJobFactory();

var jobKey = new JobKey("HelloWorldJob");
q.AddJob<HelloWorldJob>(opts => opts.WithIdentity(jobKey));
q.AddTrigger(opts => opts
.ForJob(jobKey)
.WithIdentity("HelloWorldJob-trigger")
.WithCronSchedule("0/5 * * * * ?"));
});

services.AddQuartzHostedService(
q => q.WaitForJobsToComplete = true);
}

Html/Javascript前端:下面这个例子:教程:调用ASP。. NET Core web API with JavaScript | Microsoft Docs

<form action="javascript:void(0);" method="POST" onsubmit="addJob()">
<input type="text" id="add-name" placeholder="New job">
<input type="submit" value="Add">
</form>
<script>
function addJob() {
const addNameTextbox = document.getElementById('add-name').value.trim();

const item = {
jobType: "HelloWorldJob",
durable: true,
requestsRecovery: false,
replace: false
};

fetch(`${uri}/DEFAULT/${addNameTextbox}`, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item)
})
.then(response => console.log(response))
.then(() => {
getJobs();
addNameTextbox.value = '';
})
.catch(error => console.error('Unable to add job.', error));
}
</script>

我已经尝试更新API以在url中包含jobType,然后它给出了不同的错误:

Job class cannot be null
at Qurtz.Impl.JobDetilImpl.set_JobType(Type value)

您需要提供程序集限定名作为作业类型。问题在这里:

jobType: "HelloWorldJob",

jobType应该类似于"MyNameSpace.JobType, MyAssembly"——你可能会把它写在Console.WriteLine(typeof(HelloWorldJob).AssemblyQualifiedName)的控制台——你可以忽略版本等,只需要类型名和命名空间和程序集名。

还请注意,您的设置有安全隐患,因为您允许从UI传递CLR类型。

API控制器更改:

正如上面提到的Marko, jobType需要完全限定的名称,但是在我的情况下,汇编引用不是必要的,因为我在同一个汇编中有工作。

[HttpPut]
[Route("{jobGroup}/{jobName}/{jobType}/{replace}/new")]
public async Task NewJob(string schedulerName, string jobGroup,
string jobName, string jobType, bool replace = false)
{
//Note: Job added without a trigger must be durable.
var scheduler = await GetScheduler(schedulerName).ConfigureAwait(false);
var jobDetail = new JobDetailImpl(jobName, jobGroup, 
Type.GetType("QuartzApi.Jobs." + jobType), true, false);
await scheduler.AddJob(jobDetail, replace).ConfigureAwait(false);
}

JavaScript取回查询更改:

删除JSON正文标签,并在url中添加额外的参数。注意这是一个没有触发器的作业。在稍后的阶段,jobType可以是一个变量,现在它包含在fetch字符串中。

function addJob() {
const addNameTextbox = document.getElementById('add-name').value.trim();
fetch(`${uri}/DEFAULT/${addNameTextbox}/HelloWorldJob/false/new`, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(response => console.log(response))
.then(() => {
getJobs();
addNameTextbox.value = '';
})
.catch(error => console.error('Unable to add job.', error));
}

运行UI请求以添加作业,现在无需触发器即可添加作业(将在单独的部分中进行处理)。为了确认,然后我在浏览器中运行API请求来获取正在运行的调度程序的所有作业,使用:[https://localhost: 44379/api/调度器/QuartzScheduler/工作)导致:

[{"name":"HelloWorldJob","group":"DEFAULT"},{"name":"TestJob","group":"DEFAULT"}]

这意味着一些事情:

  1. 在主体中传递JSON对象不会将其与API函数参数关联。我需要在url字符串中添加所有参数来使用它们。也许有办法使用body参数。
  2. 现在,类在API中被正确引用,我可以继续通过UI传递类名,没有名称空间和汇编,以保持其安全,因为类在构建时在项目中定义。
  3. 添加控制台。API函数的Writeline在运行时没有返回任何输出。

最新更新