I've been working with Azure Notification Hubs for awhile. However, I created a new Notification Hub for a new project and I've noticed some very odd behavior. Whenever I create a registration its ExpirationDate is set to 12/31/9999 7:59:59.
So, for some, I suppose this may be a benefit, but I'd like to expire mine after a certain period of inactivity. I looked through the RegistrationDescription object and found an ExpirationTime but it's read only...
How do I set this? Is this just a bug in Azure? Maybe a flag I'm missing from Azure configuration?
You can do that, but on hub level, not on registration level. Check out Improved Per Message Telemetry and device expiry for Notification Hubs blog post:
To take advantage of this expiry change, simply update your
notification hub’s Time To Live property. This can be done through
REST or our .NET SDK:
var namespaceManager = NamespaceManager.CreateFromConnectionString("connectionstring");
NotificationHubDescription hub = namespaceManager.GetNotificationHub("foo");
hub.RegistrationTtl = TimeSpan.MaxValue;
namespaceManager.UpdateNotificationHub(hub);
To do that via the REST API, check out Update Notification Hub method, which takes NotificationHubDescription body, which has a RegistrationTtl node in it. That should be a REST equivalent of the SDK code snippet above.
The documentation is outdated, I had to open a ticket with Microsoft to be able to do this in 2020.
I created a console app and added the following nuget packages -
https://www.nuget.org/packages/Microsoft.Azure.Management.NotificationHubs
https://www.nuget.org/packages/Microsoft.Azure.Management.ResourceManager.Fluent/
Install-Package Microsoft.Azure.Management.NotificationHubs -Version 2.3.2-preview
Install-Package Microsoft.Azure.Management.ResourceManager.Fluent -Version 1.34.0
Then I wrote this method -
private async Task SetNotificationHubRegistrationTimeToLive()
{
// Login to Azure using az login
// az account set -s <name or ID of subscription> to set the proper subscription
// Get credentials: "az ad sp create-for-rbac --sdk-auth"
// See https://learn.microsoft.com/en-us/cli/azure/get-started-with-azure-cli?view=azure-cli-latest and https://learn.microsoft.com/en-us/azure/cloud-shell/quickstart
var clientId = "ec1b...";
var clientSecret = "oJJ6...";
var tenantId = "2b86...";
var credentials =
SdkContext
.AzureCredentialsFactory
.FromServicePrincipal(
clientId,
clientSecret,
tenantId,
AzureEnvironment.AzureGlobalCloud);
var client = new NotificationHubsManagementClient(credentials)
{
SubscriptionId = "yoursubscriptionid"
};
var resourceGroupName = "yourgroup";
var namespaceName = "yournamespace"; // this should NOT be the namespace full name beam-dev-notification-hub-namespace-free.servicebus.windows.net
var notificationHubName = "yournotificationhub";
var timeSpan = new TimeSpan(days: 90, hours: 0, minutes: 0, seconds: 0);
var registrationTtlTimeSpanString = timeSpan.ToString();
var notificationHub = await client.NotificationHubs.GetAsync(resourceGroupName, namespaceName, notificationHubName);
await client
.NotificationHubs
.CreateOrUpdateAsync(
resourceGroupName,
namespaceName,
notificationHubName,
new NotificationHubCreateOrUpdateParameters(notificationHub.Location)
{
RegistrationTtl = registrationTtlTimeSpanString
});
}
You will then see in https://portal.azure.com/ in your notification hub properties -
Related
I'm trying to get a list of App Services from a subscription so that I can filter staging sites and delete them using the Azure SDK. I'm running into the issue of not authenticating properly or not being able to see any resources on the subscription.
I have the "Owner" role on the subscription so I should have total access to the subscription and its resources however when trying to follow Microsoft's docs on authenticating (https://learn.microsoft.com/en-us/dotnet/azure/sdk/authentication) I can't seem to find a way to authenticate at the subscription level.
Here's the code I have:
var azurecreds = SdkContext.AzureCredentialsFactory
.FromServicePrincipal(
"???", //client ID
"???", //client secret
"have this", //tenant ID
AzureEnvironment.AzureGlobalCloud);
var azure = Azure
.Configure()
.Authenticate(azurecreds)
.WithSubscription("have this"); //subscription ID
//attempts with hard-coded values but not working
var appServicePlans = azure.AppServices.AppServicePlans.List();
var appServicePlans2 = azure.WebApps.List();
var appServicePlans2 = azure.AppServices.AppServicePlans.ListByResourceGroup("Staging");
As you are following this document : Authenticate with token credentials
So , as per the above document , you must have created a service principal using this command :
az ad sp create-for-rbac --sdk-auth
After you have create this service principal , you will get the below details :
From the above picture you have to copy the ClientID, Client Secret, TenantID and SubscriptionId. After you have taken a note of these mentioned details , you can put the same in the code .
var azurecreds = SdkContext.AzureCredentialsFactory
.FromServicePrincipal(
"ClientID copied from the above step", //client ID
"Client Secret Copied from the above step", //client secret
"have this", //tenant ID
AzureEnvironment.AzureGlobalCloud);
var azure = Azure
.Configure()
.Authenticate(azurecreds)
.WithSubscription("have this"); //subscription ID
//attempts with hard-coded values but not working
var appServicePlans = azure.AppServices.AppServicePlans.List();
var appServicePlans2 = azure.WebApps.List();
var appServicePlans2 = azure.AppServices.AppServicePlans.ListByResourceGroup("Staging");
I am currently working out the Microsoft Graph tutorial with C# .Net Core, and in the process I came across the following C#-method for Subscription:
[HttpGet]
public async Task<ActionResult<string>> Get()
{
var graphServiceClient = GetGraphClient();
var sub = new Microsoft.Graph.Subscription();
sub.ChangeType = "updated";
sub.NotificationUrl = config.Ngrok + "/api/notifications";
sub.Resource = "/users";
sub.ExpirationDateTime = DateTime.UtcNow.AddMinutes(15);
sub.ClientState = "SecretClientState";
var newSubscription = await graphServiceClient
.Subscriptions
.Request()
.AddAsync(sub);
Subscriptions[newSubscription.Id] = newSubscription;
if (subscriptionTimer == null)
{
subscriptionTimer = new Timer(CheckSubscriptions, null, 5000, 15000);
}
return $"Subscribed. Id: {newSubscription.Id}, Expiration: {newSubscription.ExpirationDateTime}";
}
and wanted to know how I can change it for sharepoint lists instead of users.
If I change it to /sites/{site-id} or similar it does not work. (see sub.Resource)
Github-Link: MS Repo
Microsoft Graph API uses a webhook mechanism to deliver change notifications to clients. Using the Microsoft Graph API, an app can subscribe to changes for list under a SharePoint site.
Resource Path - Changes to content within the list:
/sites/{id}/lists/{id}
For details round how to subscribe to and handle incoming notifications, see Set up notifications for changes in user data
Also make sure you check necessary permissions needed here.
I found the solution myself with the sub.Resource: /sites/{site-id}/lists/{list-id}
I'm having trouble adding a Team to a Group previously created with Microsoft Graph.
I am using the Microsoft Graph .NET Client Library (1.19.0) to work with Microsoft Graph, following the .NET Core tutorial here.
Authentication is made with the client flow (console running as a deamon) and I have no problems building a graphClient or authenticating:
// Auth info
var tenantId = "xxx";
var clientId = "xxx";
var clientSecret = "xxx";
var scopes = new List<string> { "https://graph.microsoft.com/.default" };
// Create ConfidentialClientApplication
var confidentialClientApplication = ConfidentialClientApplicationBuilder.Create(clientId)
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
.WithClientSecret(clientSecret)
.Build();
// Create authenticationProvider
ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(confidentialClientApplication, scopes[0]);
// Create graph client
// Use graph BETA endpoint
var baseUrl = "https://graph.microsoft.com/beta/";
var graphServiceClient = new GraphServiceClient(baseUrl, authenticationProvider);
Or creating a group:
var groupName = "Team group";
var groupDescription = "Awesome group";
var group = new Group
{
DisplayName = groupName,
Description = groupDescription,
GroupTypes = new List<string> { "Unified" },
Visibility = "Private",
MailNickname = groupName.Replace("", string.Empty).ToLower(),
MailEnabled = false,
SecurityEnabled = false
};
// Send the POST request to create group
group = await graphServiceClient.Groups.Request().AddAsync(group);
But when adding a Team to the new group:
var team = new Team();
await graphServiceClient
.Groups[group.Id]
.Team
.Request()
.PutAsync(team);
I get the following error:
Code: InvalidRequest
Message: Could not find member '#odata.type' on object of type 'Team'. Path '['#odata.type']', line 1, position 15.
Inner error:
AdditionalData:
request-id: xxx
date: 2019-10-30 09:12:04
ClientRequestId: xxx
But when serializing the team-model to JSON the result is:
{"#odata.type":"microsoft.graph.team"}
Which would suggest that there is an OData Member with a type of Team.
I've tried to add both NuGet packages Microsoft.AspNet.OData and Microsoft.Data.OData as per this suggestion here: Could not find member '#odata.type' on object of type 'TeamMemberSettings', but it didn't work.
I've also tried calling the endpoint directly with an HttpRequest which yielded the same result. I also tried using the same code in a .NET Core and .Net Framework app.
While you can repoint the Microsoft Graph SDK to the Beta version, it will still only use the v1.0 data models. To actually use the Microsoft Graph Beta, you should use the Microsoft Graph Beta SDK.
Install-Package Microsoft.Graph.Beta -Version 0.8.0-preview
You're also using a deprecated endpoint that will be removed before the end of the year. From the documentation:
This API is in the process of being deprecated in favor of Create team, and will be removed by the end of 2019. For details about how to create a team from a group, see examples 4 and 5 in Create team.
To create a Team from a Group, you issue a POST like this:
await graphServiceClient
.Groups[group.Id]
.Team
.Request()
.PostAsync(team);
Also, keep in mind that this note from the documentation:
If the group was created less than 15 minutes ago, it's possible for the Create team call to fail with a 404 error code due to replication delays. We recommend that you retry the Create team call three times, with a 10 second delay between calls.
I have a website called www.Request.com, when users access this site they will be able to request the creation of a new instance of another website that is already deployed in AZURE with the name www.MyTechnicalApp.com
for example when I access to www.Request.com I will request the creation of MyTechnicalApp for my company called "MyCompany", it's supposed that there is a script that will be executed by request.com website to create automatically www.MyCompany.MyTechnicalApp.com website.
would you please let me know how could I do that?
According to your description, to create a web app on Azure automatically, there are two ways to achieve this.
One: using "Windows Azure Management Libraries", this SDK is a wrapper around "Azure Service Management" API.
First, we need to do authentication with ASM API and we can refer to: Windows Azure Management Librairies : Introduction et authentification, then we will be able to create a website with something like this:
using (var AwsManagement = new Microsoft.WindowsAzure.Management.WebSites.WebSiteManagementClient(azureCredentials))
{
WebSiteCreateParameters parameters = new WebSiteCreateParameters()
{
Name = "myAws",
// this Service Plan must be created before
ServerFarm = "myServiceplan",
};
await AwsManagement.WebSites.CreateAsync("myWebSpace", parameters, CancellationToken.None);
}
Two: We can create a web site by using a POST request that includes the name of the web site and other information in the request body. We can check the code example for azure-sdk-for-net
use this link to get the credentials Authentication in Azure Management Libraries for Java.
https://github.com/Azure/azure-libraries-for-java/blob/master/AUTH.md
The below link helped me to find the answer.
static void Main(string[] args)
{
try
{
var resourceGroupName = "your ressource group name";
var subId = "64da6c..-.......................88d";
var appId = "eafeb071-3a70-40f6-9e7c-fb96a6c4eabc";
var appSecret = "YNlNU...........................=";
var tenantId = "c5935337-......................19";
var environment = AzureEnvironment.AzureGlobalCloud;
var credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal(appId, appSecret, tenantId, AzureEnvironment.AzureGlobalCloud);
var azure = Microsoft.Azure.Management.Fluent.Azure
.Configure()
.Authenticate(credentials)
.WithSubscription(subId);
azure.AppServices.WebApps.Inner.CreateOrUpdateHostNameBindingWithHttpMessagesAsync(resourceGroupName, "WebSiteName", "SubDomainName",
new HostNameBindingInner(
azureResourceType: AzureResourceType.Website,
hostNameType: HostNameType.Verified,
customHostNameDnsRecordType: CustomHostNameDnsRecordType.CName)).Wait();
}
catch (Exception ex)
{
}
}
I'm looking to start an Azure runbook from a c# application which will be hosted on an Azure web app.
I'm using certificate authentication (in an attempt just to test that I can connect and retrieve some data)
Here's my code so far:
var cert = ConfigurationManager.AppSettings["mgmtCertificate"];
var creds = new Microsoft.Azure.CertificateCloudCredentials("<my-sub-id>",
new X509Certificate2(Convert.FromBase64String(cert)));
var client = new Microsoft.Azure.Management.Automation.AutomationManagementClient(creds, new Uri("https://management.core.windows.net/"));
var content = client.Runbooks.List("<resource-group-id>", "<automation-account-name>");
Every time I run this, no matter what certificate I use I get the same error:
An unhandled exception of type 'Hyak.Common.CloudException' occurred in Microsoft.Threading.Tasks.dll
Additional information: ForbiddenError: The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription.
I've tried downloading the settings file which contains the automatically generated management certificate you get when you spin up the Azure account... nothing I do will let me talk to any of the Azure subscription
Am I missing something fundamental here?
Edit: some additional info...
So I decided to create an application and use the JWT authentication method.
I've added an application, given the application permissions to the Azure Service Management API and ensured the user is a co-administrator and I still get the same error, even with the token...
const string tenantId = "xx";
const string clientId = "xx";
var context = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenantId));
var user = "<user>";
var pwd = "<pass>";
var userCred = new UserCredential(user, pwd);
var result = context.AcquireToken("https://management.core.windows.net/", clientId, userCred);
var token = result.CreateAuthorizationHeader().Substring("Bearer ".Length); // Token comes back fine and I can inspect and see that it's valid for 1 hour - all looks ok...
var sub = "<subscription-id>";
var creds = new TokenCloudCredentials(sub, token);
var client = new AutomationManagementClient(creds, new Uri("https://management.core.windows.net/"));
var content = client.Runbooks.List("<resource-group>", "<automation-id>");
I've also tried using other Azure libs (like auth, datacentre etc) and I get the same error:
ForbiddenError: The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription.
I'm sure it's just 1 tickbox I need to tick buried somewhere in that monolithic Management Portal but I've followed a few tutorials on how to do this and they all end up with this error...
public async Task StartAzureRunbook()
{
try
{
var subscriptionId = "azure subscription Id";
string base64cer = "****long string here****"; //taken from http://stackoverflow.com/questions/24999518/azure-api-the-server-failed-to-authenticate-the-request
var cert = new X509Certificate2(Convert.FromBase64String(base64cer));
var client = new Microsoft.Azure.Management.Automation.AutomationManagementClient(new CertificateCloudCredentials(subscriptionId, cert));
var ct = new CancellationToken();
var content = await client.Runbooks.ListByNameAsync("MyAutomationAccountName", "MyRunbookName", ct);
var firstOrDefault = content?.Runbooks.FirstOrDefault();
if (firstOrDefault != null)
{
var operation = client.Runbooks.Start("MyAutomationAccountName", new RunbookStartParameters(firstOrDefault.Id));
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Also in portal:
1) Application is multitenant
2) Permissions to other applications section - Windows Azure Service Manager - Delegated permissions "Access Azure Service Management(preview)"
Ensure that your Management certificate has private key and was not made from the .CER file. The fact that you're not supplying a password when generating the X509Certificate object makes me think you're using public key only
Ensure that your Managemnet's certificate public key (.CER file) has been uploaded to the Azure management portal (legacy version, Management Certificate area)
Use CertificateCloudCredentials and not any other credential type of an object
Ok, stupid really but one of the tutorials I followed suggested installing the prerelease version of the libs.
Installing the preview (0.15.2-preview) has fixed the issue!