The new ‘dotnet nuget why’ command released in dotnet 9.0 makes it easy to track down the parent of a transitive NuGet dependency:
dotnet nuget why .\SolutionName.sln System.Net.Http
The new ‘dotnet nuget why’ command released in dotnet 9.0 makes it easy to track down the parent of a transitive NuGet dependency:
dotnet nuget why .\SolutionName.sln System.Net.Http
In build pipeline set the desired build number format. The default is: 0.1.$(Rev:r) and will produce versions with patch increasing for every build
In the release pipeline using one or more artefacts from the build pipeline the primary artefact will be used to populate the Build.X variables.
Set the ‘Release name format’ to: PRODUCTID $(Build.Buildnumber) (release $(Rev:r)). This will produce the following release numbers:
Edit: Instead of manually typing the product ID it could make sense to use the pipeline name. So the release name format would be ‘$(Release.DefinitionName) $(Build.Buildnumber) (release $(Rev:r))’
The release revision will increase every time the same build is deployed multiple times (usually during debugging of the release pipeline). New version of the build will reset the release counter back to 1.
This setup allows developers to easily see how builds and releases are related. For even more transparency the build version could be stamped into the assemblies being built.
Follow these steps to migrate away from the Azure Function’s consumption plan to a regular App Service Plan.
Credit goes to DeV1l: https://github.com/Azure/Azure-F5unctions/issues/15
In UWP it is not possible to show multiple windows for a single app. Depending on the usage, the user might expect secondary windows to close once the main window closes.
There are two problems to solve to make this happen:
Both turned out to be harder than expected.
For the first issue, one might expect Window.Current.Closed or Window.Current.CoreWindow.Closed to be signalled when the window is closed. This is not the case when a secondary window is open. After trying several other events, the ApplicationView.Consolidated event was the only one that I had success with. It would appear that when multiple windows are opened, the main window is not actually closed, but just hidden.
For the second issue, I likewise tried calling several Close methods to get the second window to close. I initially stayed away from Application.Current.Exit because the documentation says it should not be called, but the MSDN article for multiple views in UWP actually recommends invoking it to close down the main window and thereby all secondary windows as well.
So the final solution ended up being:
ApplicationView.GetForCurrentView().Consolidated += (ss, ee) =>
(ss, ee) => {Application.Current.Exit();};
Swagger 2.0 supports specifying both host, scheme and base path directly in the swagger document. By default SwashBuckle does not set any values for these properties in the swagger document.
The following snippet will dynamically add the properties taken from the request to the swagger document:
app.UseSwagger(c =>
{
c.PreSerializeFilters.Add((swaggerDoc, httpReq) => {
swaggerDoc.Host = httpReq.Host.Value;
swaggerDoc.Schemes = new List<string>() { httpReq.Scheme };
swaggerDoc.BasePath = httpReq.PathBase;
});
});
After resetting the data for my app locally and then deleting it I encountered the following error: “DEP0700 : Registration of the app failed. Another user has already installed a packaged version of this app. An unpackaged version cannot replace this. The conflicting package is xxx and it was published by CN=xxx.”
For some reason the app was still on the system for another user. I ended up having to run powershell as an administrator and running the following snippet to delete the app completely from the system:
get-appxpackage -all | where name -eq “17402Qua.xxx” | remove-appxpackage
While trying out migrating a few old projects to ASP.NET Core 1.1, I stumbled upon this error when trying to the build the project.
For some reason VS does not inform about which specific references are missing. Imagine the following scenario:
Library A -> Library B
Library C -> Library A
If Library A expose any types from Library B, then C would require a direct reference to B. However, if A does not expose any of B’s types, then C can reference A without a direct reference to B.
So, VS 2017 will give you ‘Cannot find project info for (…)’ error when you don’t have the necessary direct references. Unlike previously, it will not inform which dependencies are required.
Edit: Seems the error occurs for several different issues. See more on this github issue.
I kept getting this error in both VS2017 and 2017.3 Preview. The issue apparently appears if you change your primary MSA e-email.
The solution is to reset the identity service for VS. So close all instance of VS and delete the following folder: %LOCALAPPDATA%\.IdentityService.
At first I only needed the reverse proxy for a JSON rest API. Soon, however, it was expanded to also cover HTML content. Thus the below update to make sure any URLs in the HTML was replaced to correctly match the reverse proxy server and not the internal server:
public class ProxyHandler : DelegatingHandler
{
private readonly string redirectUrl;
public ProxyHandler(string redirectUrl)
{
this.redirectUrl = redirectUrl;
}
private async Task<HttpResponseMessage> RedirectRequest(HttpRequestMessage request, CancellationToken cancellationToken)
{
var redirectLocation = redirectUrl;
var localPath = request.RequestUri.LocalPath.Replace("ExternalVirtualPath", "InternalVirtualPath");
var client = new HttpClient(new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate });
var clonedRequest = await HttpRequestMessageExtensions.CloneHttpRequestMessageAsync(request);
clonedRequest.RequestUri = new Uri(redirectLocation + localPath);
var httpResponseMessage = await client.SendAsync(clonedRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
httpResponseMessage.Headers.Add("X-ReverseProxy", "true");
if (httpResponseMessage.Content?.Headers?.ContentType != null)
{
if (httpResponseMessage.Content.Headers.ContentType.MediaType == "text/html")
{
var content = await httpResponseMessage.Content.ReadAsByteArrayAsync();
var stringContent = Encoding.UTF8.GetString(content);
var newContent = stringContent.Replace("InternalVirtualPath", "ExternalVirtualPath");
httpResponseMessage.Content = new StringContent(newContent, Encoding.UTF8, "text/html");
}
}
return httpResponseMessage;
}
protected override
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
return RedirectRequest(request, cancellationToken);
}
}
Updated: Be sure to check my follow up post
Due to infrastructure limitations my current team was in need of a reverse proxy that could point to our ASP.NET Web API endpoint. After failing to get IT to setup a reverse proxy in the load balancer I ended up experimenting with a reverse proxy based on a simple implementation using Web API.
The first requirement is to intercept all requests made to the reverse proxy endpoint. Fortunately the Web API pipeline allows this via the DelegatingHandler:
public class ProxyHandler : DelegatingHandler{}
public class WebApiConfig
{
public static void Configure(HttpConfiguration config)
{
config.MessageHandlers.Add(new ProxyHandler());
config.Routes.MapHttpRoute("abe", "{*path}");
}
}
The configuration above adds the ProxyHandler to the general pipeline thus allowing it to intercept all requests which are processed by the Web API pipeline. Then a single catch-all route is added to make sure all requests are processed by the pipeline.
In the proxy delegating handler all requests must now be forwarded to the desired location:
public class ProxyHandler : DelegatingHandler
{
private async Task<HttpResponseMessage> RedirectRequest(HttpRequestMessage request, CancellationToken cancellationToken)
{
var redirectLocation = "http://localhost:61948";
var localPath = request.RequestUri.LocalPath;
var client = new HttpClient();
var clonedRequest = await HttpRequestMessageExtensions.CloneHttpRequestMessageAsync(request);
clonedRequest.RequestUri = new Uri(redirectLocation + localPath);
return await client.SendAsync(clonedRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
}
protected override
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
return RedirectRequest(request, cancellationToken);
}
}
I experienced some problems forwarding GET requests which is why the above code clone the entire HttpRequestMessage via the below snippet found on stack overflow:
public static class HttpRequestMessageExtensions
{
public static async Task<HttpRequestMessage> CloneHttpRequestMessageAsync(HttpRequestMessage req)
{
var clone = new HttpRequestMessage(req.Method, req.RequestUri);
var ms = new MemoryStream();
if (req.Content != null)
{
await req.Content.CopyToAsync(ms).ConfigureAwait(false);
ms.Position = 0;
if ((ms.Length > 0 || req.Content.Headers.Any()) && clone.Method != HttpMethod.Get)
{
clone.Content = new StreamContent(ms);
if (req.Content.Headers != null)
foreach (var h in req.Content.Headers)
clone.Content.Headers.Add(h.Key, h.Value);
}
}
clone.Version = req.Version;
foreach (var prop in req.Properties)
clone.Properties.Add(prop);
foreach (var header in req.Headers)
clone.Headers.TryAddWithoutValidation(header.Key, header.Value);
return clone;
}
}
I’m very impressed by the elegance of both Web API but more so the way the HttpRequestMessage/HttpResponseMessage is reused between Web API and HttpClient.
I tested the reverse proxy solutions against our current API and all our GET/POST requests went through. Furthermore all exception message was passed through the proxy as well.