Azure WebJobs provide a more or less hidden API inside of KUDU called WebJobs API. This API is REST based webservice and it can be used to manage your jobs programmatically. Unfortunately, today it does not exist any SDK for this API. For this reason you will have to deal with API-REST endpoint natively.
In this post I will shortly explain how to do this.
First of all you have provide authorization token to be able to use this service. For authorization purposes a common deployment credential is uses. That means, you cannot use your MS-Account or AAD credentials. Fortunately, this is not a disadvantage, because you don’t have to pay with AAD and you don’t have to deal with AAD at all.
To obtain credentials, go to your site in azure portal and download publish credentials:
After download open credentials file and look for username and password:
<publishData>
<publishProfile profileName="CSharpWebJobs - Web Deploy"
publishMethod="MSDeploy"
publishUrl="web.scm.azurewebsites.net:443"
msdeploySite="web"
userName="$***"
userPWD="****"
destinationAppUrl="http://csharpwebjobs.azurewebsites.net"
SQLServerDBConnectionString=""
mySQLDBConnectionString=""
hostingProviderForumLink=""
controlPanelLink=http://windows.azure.com
…
</publishData>
Note that you don’t have to create any deployment credentials to do this. For example, in Azure portal there is a place to set the deployment username and password. This kind of credential is not required, because WebJobs API uses built in deployment credentials. I know this sounds a bit wired, but it is how it works, for now.
As next you should implement appropriate code, which will consume the WebJob API. Following example shows how to get the list of currently installed jobs and how to create new jobs:
public static void WebApiSample() { string siteName = "YOUR SITE NAME";
String username = $"${siteName}"; String password = "***"; String encoded = System.Convert.ToBase64String( System.Text.Encoding.GetEncoding("ISO- 8859-1").GetBytes(username + ":" + password)); client = new HttpClient(); client.BaseAddress = new Uri($"https://{siteName}.scm.azurewebsites.net/"); client.DefaultRequestHeaders.Add("Authorization", $"Basic {encoded}");
var res = getJobsAsync().Result; for (int i = 36; i < 100; i++) { deployJobAsync($"myJob-{i}", "C:\CreateWebJobWithCode\JOB.zip").Wait(); } }
private static async Task<JObject> getJobsAsync() { var response = await client.GetAsync("api/webjobs"); var result = await response.Content.ReadAsStringAsync(); return JObject.Parse(result); } private static async Task deployJobAsync(string jobName, string zipFileName) { using (StreamReader reader = new StreamReader(zipFileName)) { StreamContent streamContent = new StreamContent(reader.BaseStream); var response = await client.PutAsync($"api/zip/site/wwwroot/App_Data/jobs/continuous/{jobName}/", streamContent); var result = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) return; else throw new Exception(result); } } |
As you see in the code above, you will be required to provide the name of your site and password. Notice, the username is combined as $YOURSITENAME. This is why you don’t have to create user for deployment. Method getJobsAsync() demonstrates how to return the list of all services. Method deployJobAsync() demonstrates how to deploy a job from ZIP file. Note content of the ZIP file, is the same as if you would deploy the job usual way by using Visual Studio or Azure Portal.
How to enlist all jobs inside of site?
https://jobname.scm.azurewebsites.net/azurejobs/#/jobs
How to get job details?
https://jobname.scm.azurewebsites.net/azurejobs/#/jobs/continuous/myJob-55
Possible Errors
1. Following error means that you URL is not correct:
"No route registered for '/deployments/api/webjobs'"
Correct relative URL would be:
“/api/webjobs'"
2. Please note, that if you are creating many jobs (approx. 30-35) the WebJob API will block for a while. That means, you will not be able to manage jobs by API and also in portal. After approx. 10 min. WebJobs endpoint will became available again.
Posted
Nov 28 2016, 07:25 AM
by
Damir Dobric