Add WebJobs to WebApp with Azure Fluent API - azure

Is it possible to use the Azure Fluent API to add a WebJob to a WebApp? I'm not finding any documentation describing this.

I believe the answer is no, and that you are required to use the Azure Kudu WebJob API
More information about that can be found:
https://github.com/projectkudu/kudu/wiki/WebJobs-API
https://blogs.msdn.microsoft.com/benjaminperkins/2016/02/01/using-the-azure-webjob-api/

As Lachie said, it seems that there is no Fluent API support to add WebJobs, you could use WebJobs KUDU API to achieve it.
I do a demo for that. It works correctly in my site. The following is my detail steps:
Preparation:
1.The WebJob API require Basic Authentication using the publishing credentials, you could go to your webapp in azure portal to click Get publish profile and download it to get username and userpassword.
2.Zip the WebJob to be published file.
Steps:
1.Create a C# console project.
2.Add the following code in the Program.cs file.
string userName = "$name";
string userPassword = "pass";
string webAppName = "webappname";
string webJobName = "webjobname";
var base64Auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{userName}:{userPassword}"));
var file = File.ReadAllBytes(#"webjob zip file path");
MemoryStream stream = new MemoryStream(file);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Basic " + base64Auth);
client.DefaultRequestHeaders.Add("ContentType", "application/zip");
var baseUrl = new Uri($"https://{webAppName}.scm.azurewebsites.net/");
var requestURl = baseUrl + "api/continuouswebjobs/"+webJobName;
var httpContent = new StreamContent(stream);
httpContent.Headers.Add("Content-Disposition", "attachement;filename="+ webjob.exe);
var response2 = client.PutAsync(requestURl, httpContent).Result;
}
Note: The filename should be in the Content-Dispostion header. Here I deploy the continuous webjob, if you want to deploy trigger webjob, you could change continuouswebjobs to triggeredwebjobs.
3.Test from the local.
4.Check the published result on azure.

Related

Upload file to the SharePoint site with Azure App credentials

I have
Registered Azure Application
that have full control permissions to the SharePoint site
and these variables
SharePoint Site Url
TenantId
ClientId
ClientSecret
I need to upload a document to the SharePoint Site Folder.
I tried to use PnP Core SDK but I am not able to configure the Authentication, it seems that there is no authentication provider to just accept plain password (UsernamePasswordAuthenticationProvider does not accept name of the application as a username).
Overall the PnP Core SDK is adding a lot of complexity to my console application because it depends on Microsoft.Extensions.Hosting.Host.
is there a way how to authenticate via PnP or should I use REST API directly?
Alternatively the PnP Framework that will be deprecated (if I understand the documentation correctly) can authenticate towards Azure Application, but this is only documentation I found.
Any idea or recommendation?
Update
When I try this (PnP Framework)
using Microsoft.SharePoint.Client;
using PnP.Core.Model.SharePoint;
using PnP.Framework;
ClientContext context =
new AuthenticationManager()
.GetACSAppOnlyContext(
siteUrl: "siteUrl",
appId: "clientId",
appSecret: "password");
IFolder? folder = (IFolder?)context.Web.Folders.Where(f => f.Name == directory).FirstOrDefault();
if (folder == null) throw new Exception("Folder not found.");
folder.Files.Add(filename, content, overwrite);
I am getting this exception
Microsoft.SharePoint.Client.CollectionNotInitializedException: 'The
collection has not been initialized. It has not been requested or the
request has not been executed. It may need to be explicitly
requested.'
Any Idea how to explicitly request the collection?
According to my research and testing, if you want to connect to SharePoint Online with Azure App credentials, you can use the following code, and then upload file to SharePoint:
string siteUrl = "https://contoso.sharepoint.com/sites/demo";
using (var cc = new AuthenticationManager().GetACSAppOnlyContext(siteUrl, "[Your Client ID]", "[Your Client Secret]"))
{
cc.Load(cc.Web, p => p.Title);
cc.ExecuteQuery();
Console.WriteLine(cc.Web.Title);
};
Here is a document about upload file to SharePoint, you can refer to the code in this document: Upload a document to a SharePoint list from Client Side Object Model
Also, you can try to install Microsoft.SharePointOnline.CSOM to fix the error:
Microsoft.SharePoint.Client.CollectionNotInitializedException: 'The
collection has not been initialized. It has not been requested or the
request has not been executed. It may need to be explicitly
requested.'
More information for reference: Granting access using SharePoint App-Only
Create ClientContext
using Microsoft.SharePoint.Client;
using PnP.Framework;
ClientContext _context =
new AuthenticationManager()
.GetACSAppOnlyContext(
siteUrl: siteUrl,
appId: appId,
appSecret: appSecret);
Method for uploading the file
public void UploadFile(Stream stream, string listTitle, string directory, string filename, bool overwrite)
{
List list = _context.Web.Lists.GetByTitle(listTitle);
var url = Path.Combine(directory, filename);
var file = new FileCreationInformation() { ContentStream = stream, Overwrite = overwrite, Url = url };
var addedFile = list.RootFolder.Files.Add(file);
_context.Load(addedFile);
_context.ExecuteQuery();
}
Call example
UploadFile(stream, "Documents", "Shared Documents/FooSubFolder/", "filename.txt", true)

How to update Azure App Configuration Settings using Code (.Net Core)

I have an Azure app registered on Azure portal which is created in .NET Core 2.0 This app reads some config value from the Application settings section from the portal as shown in below image.
Now at some stage I want to update those config value from code. I have searched for many article but not found how to update Azure Application settings from code. Can any one have an idea or suggestion that How can I update Azure Application settings using .NET Core 2.0 C#?
This can be accomplished using Azure.ApplicationModel.Configuration nuget package.
In particular, the SetConfigurationSetting method seems to do what you are after.
string connectionString = "<connection_string>";
var client = new ConfigurationClient(connectionString);
ConfigurationSetting setting = client.SetConfigurationSetting("some_key","new_value");
Note: This package is in preview
You could use c# to call the REST API Web Apps - Update Application Settings manually.
PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/config/appsettings?api-version=2019-08-01
For more details about how to call Azure REST API in c#, you could refer to this link.
If you want to use c# to do it, you could try with Microsoft.Azure.Management.Fluent package, the below is the sample code, you could have a try.
string tenantId = "*******";
string clientSecret = "********";
string clientId = "********";
string subscriptionId = "*******";
var azureCredentials = new AzureCredentials(new
ServicePrincipalLoginInformation
{
ClientId = clientId,
ClientSecret=clientSecret
}, tenantId, AzureEnvironment.AzureGlobalCloud) ;
var _azure = Azure
.Configure()
.WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
.Authenticate(azureCredentials)
.WithSubscription(subscriptionId);
var appResourceId = "/subscriptions/**********/resourcegroups/*******/providers/Microsoft.Web/sites/***"; //Get From WebApp -> Properties -> Resource ID
var webapp = _azure.WebApps.GetById(appResourceId);
webapp.Update()
.WithAppSetting("test", "testvalue")
.Apply();
The library has been changed to Azure.Data.AppConfiguration.
Azure.ApplicationModel.Configuration is depracated
This is an addendum to George Chen's answer.
To avoid the "Operation returned an invalid status code 'Forbidden' exception after calling _azure.WebApps.GetById(appResourceId), you need to ensure the service principal associated with the Azure Credential has contributor access to the subscription the web app is in. For more details refer to https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal.

Authenticate Azure Management SDK in .NET Core?

I'm running ASP.NET Core application (.Net Core 3.0) and have referenced nuGet package Microsoft.Azure.Management.WebSites. It seems like there are half a dozen ways to connect to Azure and I'm hoping that is the correct one for my environment.
I'm attempting to instantiate a WebSiteManagementClient so that I can modify some AppService settings (scale service plan up/down). To that end, I need an instance of ServiceClientCredentials. I can't seem to find a way to get the proper credentials together.
I've followed several different articles, all of them advocate a different method.
What's the easiest way to get authenticated against the Azure Management SDK?
Ideally, avoiding Azure Active Directory. I've attempted multiple times trying to set up an App Registration with the appropriate permissions, and I can't seem to get it together.
The app connecting and making the change will be an ASP.NET website running in Azure itself, if it makes a difference.
Thanks in advance!
Code so far:
using Microsoft.Azure.Management.WebSites;
var credentials = await GetCredentials(); // <-- ???
WebSiteManagementClient client = new WebSiteManagementClient(credentials);
client.SubscriptionId = "xxx-xxx-xxxx-xxxx";
Try this :
static void Main(string[] args)
{
string tenantId = "<your tenant ID>";
string clientId = "<your azure ad app ID>";
string clientSecret = "<azure ad app secret>";
string subscriptionId = "<your subscription ID>";
WebSiteManagementClient client = new WebSiteManagementClient(GetCredsFromServicePrincipal(tenantId, clientId, clientSecret));
client.SubscriptionId = subscriptionId;
foreach (var ap in client.app.List()) {
Console.WriteLine(ap.Id);
}
}
private static TokenCredentials GetCredsFromServicePrincipal(String tenantId,String clientId, String clientSecret)
{
var authority = #"https://login.microsoftonline.com/" + tenantId;
var authContext = new AuthenticationContext(authority);
var credential = new ClientCredential(clientId, clientSecret);
var authResult = authContext.AcquireTokenAsync("https://management.azure.com", credential).GetAwaiter().GetResult();
return new TokenCredentials(authResult.AccessToken);
}
Result (list all website ids):
As this sample use ServicePrincipal to access your azure website resources, so you should grant associated permissions it in your subscription "Access control (IAM)" balde, such as assigning "website contributor" and "web plan contributor" to it so it has permission to manage your website resources . Hope it helps.
The new Azure.Identity library seems to be the recommended way for authenticating services within Azure. In particular the DefaultAzureCredentials() class works seamlessly in local development scenarios and in deployed code without having to make any code changes.
This is easy to use with the newer management SDKs (the ones with names like Azure.ResourceManager...) because we can just write new DefaultAzureCredentials() and pass that to the management SDK when creating a new client.
Unfortunately, the older management SDKs (the ones with names like Microsoft.Azure.Management...) do not integrate with Azure.Identity "out-of-the-box". They also do not plan to add support for Azure.Identity to these older APIs because they are instead focusing on porting everything to the newer versions.
However, not every resource in Azure has a new version management API yet and so in some cases you're stuck using the old ones. Fortunately, there is a relatively straight forward way to bridge the gap and still use Azure.Identity with those older APIs.
There's a GitHub repo which contains an example of how to achieve this. I think it's by one of the developers on the Microsoft team, but isn't officially supported by Microsoft. There is no NuGet package for it and they recommend just copying the bits you need.
I actually found that the code in that sample repo was overly complex for my needs and in my case that all I needed was this. Note, I've copied this from my F# project without testing it, so I might have made a mistake in the conversion to C#, but hopefully it's close enough that you get the idea.
class AzureIdentityFluentCredentialAdapter : AzureCredentials
{
public AzureIdentityFluentCredentialAdapter(string tenantId)
: base(default(DeviceCredentialInformation), tenantId, AzureEnvironment.AzureGlobalCloud)
{
}
public override Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var creds = DefaultAzureCredential() // Use the new Azure.Identity library to get access tokens
var accessToken = await creds.GetTokenAsync(
new TokenRequestContent(new [] { "https://management.azure.com/.default" }),
cancellationToken);
return await TokenCredentials(accessToken.Token)
.ProcessHttpRequestAsync(request, cancellationToken);
}
}
This example doesn't do any token caching, but for my purposes I wasn't too bothered about this. It's also hardcoded the scope that I request the token for because I knew I was only going to be using this with the Azure management API.

Getting information of Azure app insights via RestAPI

I have deployed a web job to Azure and also have a request/response graphs associated with it (insight). I want to extract the graph information and display it on another web page (as an embedded graph). Please see the attached screenshot for my azure dashboard which have the graph.
Is there a RESTApi or any SDK available to get graph(app insight) from azure and display it in the web page?
(hope this is not related to powerbi)
If you want get the requests and AverageResponseTime metrics We could use the Monitor API or Microsoft.Azure.Management.Monitor to do that. I do a demo to get the Azure WebApp request metrics demo. Other supported metrics supported metrics please refer to Azure Monitor Metrics List.
Preparetion:
Registry Azure Active Directory application and assign Role
Then we can get the tenantId,clientId,clientSecretKey
var azureTenantId = "tenantId";
var azureSecretKey = "clientSecretKey";
var azureAppId = "clientId";
var subscriptionId = "subscriptionId";
var resourceGroup = "ResourceGroup";
var webAppName = "webAppname";
var serviceCreds = ApplicationTokenProvider.LoginSilentAsync(azureTenantId, azureAppId, azureSecretKey).Result;
var client = new MonitorClient(serviceCreds) {SubscriptionId = subscriptionId};
var resourceUrl = $"subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Web/sites/{webAppName}";
var result = client.Metrics.ListWithHttpMessagesAsync(resourceUrl,metric: "Requests",interval:new TimeSpan(0,0,5,0),timespan: "2018-02-19T06:57:56Z/2018-02-20T07:57:56Z").Result;

Azure mobile service and Azure storage integration

We use Azure Mobile Services with Javascript (Node.js) back-end. The front-end is HTML/Javascript and runs as Azure Web App. We want to use Azure blob storage to store files (uploaded from front-end). I searched for a working example implementing this scenario, but I can't find it. There are examples with .NET back-end or Android/Windows Phone front-end. As a workaround it's possible to post the file to mobile service and do the storage from there, but the mobile service api body has a 1MB limit. I know I have to use a Shared Access Signature (SAS), but I don't know how to implement that. Generating the url from mobile service works. But it's not accepted when I use it in the client.
This guide is not working anymore: http://gauravmantri.com/2013/02/16/uploading-large-files-in-windows-azure-blob-storage-using-shared-access-signature-html-and-javascript/
Thanks in advance for your help!
As usually, custom APIs on mobile services are used in handling logic workflows or event triggers. So Azure mobile service limit the body size of custom APIs requests for better performance. To implement upload files from clients to Azure Storage, we recommend to leverage SAS URIs.
And lots samples use the backend project to generate the SAS URI and return back to front-end.We can leverage Azure Node.js SDK in Mobile service custom APIs scripts to generate SAS URI.
Here is the code snippet:
exports.get = function(request, response) {
var azure = require('azure');
var qs = require('querystring');
var accountName = { accountName };
var accountKey = { accountKey };
var host = accountName + '.blob.core.windows.net';
var blobService = azure.createBlobService(accountName, accountKey, host);
var startDate = new Date();
var expiryDate = new Date(startDate);
expiryDate.setMinutes(startDate.getMinutes() + 30);
startDate.setMinutes(startDate.getMinutes() - 30);
var sharedAccessPolicy = {
AccessPolicy: {
Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE,
Start: startDate,
Expiry: expiryDate
},
};
// you can custom send container name and blob name via http get request
/** e.g. var containerName = request.query.container,
blobName = request.query.blob
client side use invokeApi method, e.g.
client.invokeApi('getSAS',{
method:'GET',
parameters:{container:'mycontainer',blob:'myblob'}
})
**/
var blobSAS = blobService.generateSharedAccessSignature('mycontainer', 'myblob', sharedAccessPolicy);
var sasQueryString = qs.stringify(blobSAS.queryString);
var sasUri = blobSAS.baseUrl + blobSAS.path;
response.send(sasUri+"?"+sasQueryString);
};
You can refer to Upload images to Azure Storage from an Android device and Work with a JavaScript backend mobile service for reference.
Furthermore, for a deep understanding of generating SAS URI, you can refer to Constructing a Service SAS and Shared Access Signatures, Part 1: Understanding the SAS Model
Additionally, here is a similar example built in this architecture, Upload files to Microsoft Azure Storage from JavaScript

Resources