Azure DevOps Promote NuGet packages to Release view - azure

As part of an Azure DevOps pipeline, I would like to promote packages in our own NuGet feed to 'Release' view as part of the release build.
I have an application that traverses all project.assets.json files and find names and versions of packages used by the projects in the solution.
This list is reduced by pattern matching on names to our own packages.
Previously I have succesfully used the BuildHttpClient from Microsoft.TeamFoundation.Build.WebApi to access information about builds and build artifacts.
What are the available tools for accessing Nuget Packages, feeds and views?
The REST API is described here: https://learn.microsoft.com/en-us/rest/api/azure/devops/artifactspackagetypes/nuget/update%20package%20versions?view=azure-devops-rest-6.0, but I would hate to implement the classes myself, if there is a library for the purpose.

Nuget - Update Package Versions has a flaw - there is no {project} relevans for packages.
By adding Microsoft.VisualStudio.Services.Packaging.Client Version 16.179.0-preview we get the classes, we need as long as we are building .Net Framework 4.6.2 or later (no netstandard yet).
based on this, I built the following helper class (no exception handling or threading to keep it simple):
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Microsoft.VisualStudio.Services.NuGet.WebApi.Types;
using Microsoft.VisualStudio.Services.Packaging.Shared.WebApi;
using Newtonsoft.Json;
namespace PromotePackages
{
public class PromotePackageBatch
{
private readonly string _organization;
private readonly string _feedId;
private readonly string _token;
public PromotePackageBatch(string organization, string feedId, string token)
{
_organization = organization;
_feedId = feedId;
_token = token;
}
public void PromotePackagesToView(IDictionary<string, string> Libraries, string viewName)
{
var packs = new List<MinimalPackageDetails>();
foreach (var kvp in Libraries)
{
packs.Add(new MinimalPackageDetails
{
Id = kvp.Key,
Version = kvp.Value
});
}
using (HttpClient client = new HttpClient())
{
NuGetPackagesBatchRequest req = new NuGetPackagesBatchRequest
{
Data = new BatchPromoteData
{
ViewId = viewName
},
Operation = 0,
Packages = packs
};
var httpContent = new StringContent(JsonConvert.SerializeObject(req), Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", _token))));
var response = client.PostAsync(BuildUri(), httpContent).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
}
}
private Uri BuildUri()
{
return new Uri($"https://pkgs.dev.azure.com/{_organization}/_apis/packaging/feeds/{_feedId}/nuget/packagesbatch?api-version=6.0-preview.1");
}
}
}

By reference to this doc: Azure DevOps Services .NET SDK API Reference, searching for any managed APIs by typing in the box, but we don’t find such library which implements this Rest API: NuGet - Update Package Versions.
You could create a new issue in the MicrosoftDocs/feedback repository on GitHub for this feedback.
And now we suggest that you directly use this Rest API to implement this.

Related

Azure AppInsights end to end correlation

I am looking into Azure AppInsights for my telemetry correlation requirement. I have created 3 simple APIs that call one another in succession as below:
First Api -----> Middle Api -----> Another Api
The Api calls are made using Typed HttpClient through a simple service class. All the Api projects have Microsoft.ApplicationInsights.AspNetCore and Microsoft.Extensions.Logging.ApplicationInsights NuGets references added. I have program and service classes for all the APIs as below:
Program.cs
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
...
//App Insights
builder.Services.AddSingleton(typeof(ITelemetryChannel),
new ServerTelemetryChannel() { StorageFolder = "/tmp/myfolder" });
builder.Services.AddApplicationInsightsTelemetry();
builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
builder.Services.AddScoped<IWeatherService, DummyWeatherService>();
builder.Services.AddHttpClient<IWeatherService, DummyWeatherService>();
var app = builder.Build();
...
app.Run();
Service
using System.Net.Http.Headers;
using AppInsightsDemo.Api.Models;
namespace AppInsightsDemo.Api.Services;
public class DummyWeatherService : IWeatherService
{
private readonly IConfiguration _configuration;
private readonly HttpClient _httpClient;
public DummyWeatherService(
IConfiguration configuration,
HttpClient httpClient)
{
_configuration = configuration;
_httpClient = httpClient;
_httpClient.BaseAddress = GetMiddleApiBaseUri();
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
private Uri GetAnotherApiBaseUri()
{
var configurationSection = _configuration.GetRequiredSection("Dependencies");
var baseUri = configurationSection.GetValue<string>("MiddleApiUri")
?? throw new ArgumentException("Another Api base uri is empty");
return new Uri(baseUri);
}
public async Task<Weather?> GetWeatherAsync()
{
Weather? weather = null;
var response = await _httpClient.GetAsync("middle");
if (response.IsSuccessStatusCode)
{
weather = await response.Content.ReadAsAsync<Weather>();
}
return weather;
}
}
This is what I end up with in AppInsights sample. The third API event has the same operation id as the first two Api events have but the third event has a different parent id. I expect the third event to have the id of my middle (second) api event (localhost://7290) as its parent id and the three events show up accordingly in a hierarchy.
Can anyone please advise if I am missing some configuration or not using this SDK right? Thank you
This is rather silly of me. I configured the ApplicationInsights connection string for my first api(:7176) and last api(:7206) but missed to configure it for my middle api (:7290) though I have added ApplicationInsights service to all Api projects. It took me a while to figure out the missing connection string. Now I get a nice dependency hierarchy as below:
I guess a connection string validation might come handy. Sorry for the trouble. Thanks.

Azure Durable Functions: Can I use a startup.cs?

I have a couple of functions that I want to refactor into a Azure Durable Function, where the orchestrator calls different ActivityFunctions (the previously seperate Azure Functions). The seperate functions use a startup where I configure dependency injection and some other configurations.
Is it possible to use a startup class in a Durable Function scheme? I cannot find anything that seems to suggest this in the documentation.
If it is not possible, what other alternatives are there, for example, to define database connection string and dependency injection?
Thnx
Dependency Injection is possible in Durable Functions too.
Install and add reference to the following package from Nuget:
Microsoft.Azure.Functions.Extensions.DependencyInjection
Here's a working sample of Startup file with Dependency Injection done:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.WebJobs.Host.Bindings;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
[assembly: FunctionsStartup(typeof(MyDurableFunction.Startup))]
namespace MyDurableFunction
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var executioncontextoptions = builder.Services.BuildServiceProvider()
.GetService<IOptions<ExecutionContextOptions>>().Value;
var currentDirectory = executioncontextoptions.AppDirectory;
var environment = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT");
var config = new ConfigurationBuilder()
.SetBasePath(currentDirectory)
.AddJsonFile($"settings.{environment}.json", optional: false, reloadOnChange: false)
.AddEnvironmentVariables()
.Build();
builder.Services.AddSingleton<IMyBusinessService1>(sp =>
{
var secretFromAppSettings = config["secretKey"];
var passwordFromAppSettings = config["secretPassword"];
return new MyBusinessService1(secretFromAppSettings, passwordFromAppSettings);
});
builder.Services.AddSingleton<IDatabaseHelper, DatabaseHelper>();
builder.Services.AddLogging();
}
}
}
Hope this helps!
Yes you can use Dependency Injection similar to normal functions.
A complete example which I found in this blog

Azure connection attempt failed

I'm using the following code to connect. I can connect to other Azure Resources ok.
But for one resource I get the following error: URL and Key are correct.
{"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond"}
The Code is as follows
_searchClient = new SearchServiceClient(searchServiceName, new
SearchCredentials(apiKey));
_httpClient.DefaultRequestHeaders.Add("api-key", apiKey);
_searchServiceEndpoint = String.Format("https://{0}.{1}",
searchServiceName, _searchClient.SearchDnsSuffix);
bool result = RunAsync().GetAwaiter().GetResult();
Any ideas? thx in advance? How can I troubleshoot this?
I will show how this is done in c#
you will need a appsettings.json
you will need this code in the program.cs file
there are a lot of other files in the example from the document
that you may need to use , learn and edit for ur usecase
When working in c# and azure, always know what is unique about the file structured your solution first. This is why we build the examples from the docs as we learn the solution. Next we must study the different blocks of code that when executed deliver one feature or functionality to the solution as a whole.
appsettings.json
{
"SearchServiceName": "[Put your search service name here]",
"SearchIndexName": "hotels",
"SearchServiceAdminApiKey": "[Put your primary or secondary Admin API key here]",
"SearchServiceQueryApiKey": "[Put your primary or secondary Query API key here]"
}
Program.cs
namespace AzureSearch.SDKHowTo
{
using System;
using System.Linq;
using System.Threading;
using Microsoft.Azure.Search;
using Microsoft.Azure.Search.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Spatial;
// This sample shows how to delete, create, upload documents and query an index
static void Main(string[] args)
{
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
IConfigurationRoot configuration = builder.Build();
SearchServiceClient serviceClient = CreateSearchServiceClient(configuration);
string indexName = configuration["SearchIndexName"];
Console.WriteLine("{0}", "Deleting index...\n");
DeleteIndexIfExists(indexName, serviceClient);
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, serviceClient);
ISearchIndexClient indexClient = serviceClient.Indexes.GetClient(indexName);
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(indexClient);
ISearchIndexClient indexClientForQueries = CreateSearchIndexClient(indexName, configuration);
RunQueries(indexClientForQueries);
Console.WriteLine("{0}", "Complete. Press any key to end application...\n");
Console.ReadKey();
}
private static SearchServiceClient CreateSearchServiceClient(IConfigurationRoot configuration)
{
string searchServiceName = configuration["SearchServiceName"];
string adminApiKey = configuration["SearchServiceAdminApiKey"];
SearchServiceClient serviceClient = new SearchServiceClient(searchServiceName, new SearchCredentials(adminApiKey));
return serviceClient;
}
private static SearchIndexClient CreateSearchIndexClient(string indexName, IConfigurationRoot configuration)
{
string searchServiceName = configuration["SearchServiceName"];
string queryApiKey = configuration["SearchServiceQueryApiKey"];
SearchIndexClient indexClient = new SearchIndexClient(searchServiceName, indexName, new SearchCredentials(queryApiKey));
return indexClient;
}
private static void DeleteIndexIfExists(string indexName, SearchServiceClient serviceClient)
{
if (serviceClient.Indexes.Exists(indexName))
{
serviceClient.Indexes.Delete(indexName);
}
}
private static void CreateIndex(string indexName, SearchServiceClient serviceClient)
{
var definition = new Index()
{
Name = indexName,
Fields = FieldBuilder.BuildForType<Hotel>()
};
serviceClient.Indexes.Create(definition);
}}
Azure concepts to learn
How and why we create azure clients
Why do we use appsettings.json
What is some example file structures for azure search solutions
What coding lanague do you want to use to build that solutio
do u want to use the azure sdk
How to find and create api keys
C# concepts to learn
What is an interface and how do you use it
How to import one file in the file structure into another
How the main function works
How to call variables in to a function
How to call a function with a function
How to write server side code vs client side code
How to deploy c# code to azure
What version of c# are u using What’s is asp.net and what version will u use
What is asp.net core and what version will u use
As u can see azure and c# have a high learning curve.
Luckily you have stack overflow and documentation to research all of the above questions and more:)
For how u would troubleshoot...what I do is research each block of code in the documentation example and run all of the code locally. Then I test each block of code one at a time. Ur always testing data flowing thought the block of code. So you can just console log the result of a block a code by creating a test varable and print that varable to the console.
Because each block of Code represents one feature or functionality, each test will output either a pass or fail delivery of that feature or functionality. Thus you can design functionality, implement that design and create a test for new Feature.

Where did IDefaultKeyServices go in ASP.NET Core 2.0? What replaces it?

In ASP.NET Core 1.x the IoC container could be used to get a concrete implementation of Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IDefaultKeyServices but no such interface is registered with the IoC in ASP.NET Core 2.0. Where did IDefaultKeyServices go? Or what replaces it?
The interface looked like this:
public interface IDefaultKeyServices {
//
// Summary:
// Gets the default Microsoft.AspNetCore.DataProtection.XmlEncryption.IXmlEncryptor
// service (could return null).
IXmlEncryptor GetKeyEncryptor();
//
// Summary:
// Gets the default Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository
// service (must not be null).
IXmlRepository GetKeyRepository();
}
Microsoft documents the interface here.
I realize that this interface is in an "Internal" namespace and is subject to change (and change it did!). But how does one now get the default key repository and the default key encryptor in 2.x?
IDefaultKeyServices and its implementation DefaultKeyServices were removed with this commit.
Instances of IXmlRepository and IXmlEncryptor could be accessed via XmlRepository and XmlEncryptor properties of KeyManagementOptions.
Key storage providers article lists built-in implementations of IXmlRepository. You setup appropriate repository by calling PersistKeysTo...() extension method on IDataProtectionBuilder, e.g.:
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp\"));
or
services.AddDataProtection()
.PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Sample\keys"));
Key Encryption At Rest article lists built-in implementations of IXmlEncryptor. You setup appropriate encryptor by calling ProtectKeysWith...() extension method on IDataProtectionBuilder, e.g.:
services.AddDataProtection()
.ProtectKeysWithDpapi();
Here is a demo sample (Microsoft.AspNetCore.DataProtection NuGet required):
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp\"))
.ProtectKeysWithDpapi();
var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetService<IOptions<KeyManagementOptions>>();
var keyManagementOptions = options.Value;
var xmlRepository = keyManagementOptions.XmlRepository;
// Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository
var repositoryType = xmlRepository?.GetType();
var xmlEncryptor = keyManagementOptions.XmlEncryptor;
// Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlEncryptor
var encryptorType = xmlEncryptor?.GetType();
}
One more useful article in addition to already linked: Key management extensibility

Reading IIS settings from an ASP.app

We would like to build an Admin Checklist page that allows our network administrators to quickly view all the setting in the IIS and web config to easily trouble an issue. the web config is fairly easy but I'm not sure how to get the stuff from IIS. (App Pool Name and type, Machine Key, Anonymous Authentication, etc.) I'm sure it can be done, I just don't know how.
Thanks,
Rhonda
The information you're looking for are exposed in the IIS .Net APIs. You can find them in \windows\system32\inetsrv (they are Microsoft.Web.Administration.dll, and maybe Microsoft.Web.Management.dll).
Sample code to get ID and application pool name for each site :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Web.Administration;
namespace ConsoleApplication79
{
class Program
{
static void Main(string[] args)
{
ServerManager s = new ServerManager();
var q = s.Sites.Select(aSite => new
{
ID = aSite.Id,
AppPoolName = aSite.Applications.First().ApplicationPoolName
});
foreach (var item in q)
{
Console.WriteLine("ID: {0}, PoolName: {1}", item.ID, item.AppPoolName);
}
}
}
}

Resources