Azure publish: Failed to update API in Azure - c#

Im trying to publish my .net3.1 webapp on Azure from Visual Studio.
Visual studio fails on 'Starting to update your API' step, this is the output from visual studio:
Build started...
1>------ Build started: Project: WebApplication_XXX, Configuration: Release Any CPU ------
1>WebApplication_XXX -> C:\Users\YYYY\source\repos\WebApplication_XXX\WebApplication_XXX\bin\Release\netcoreapp3.1\WebApplication_XXX.dll
1>Done building project "WebApplication_XXX.csproj".
2>------ Publish started: Project: WebApplication_XXX, Configuration: Release Any CPU ------
WebApplication_XXX -> C:\Users\YYYY\source\repos\WebApplication_XXX\WebApplication_XXX\bin\Release\netcoreapp3.1\WebApplication_XXX.dll
npm install
npm run build -- --prod
> webapplication_xxx#0.0.0 build C:\Users\YYYY\source\repos\WebApplication_XXX\WebApplication_XXX\ClientApp
> ng build "--prod"
Generating ES5 bundles for differential loading...
ES5 bundle generation complete.
....
Publish Succeeded.
Web App was published successfully https://xxxxxxx.azurewebsites.net/
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Publish: 1 succeeded, 0 failed, 0 skipped ==========
Starting to update your API
Generating swagger file to 'C:\Users\YYYY\source\repos\WebApplication_XXX\WebApplication_XXX\bin\Release\netcoreapp3.1\swagger.json'.
Failed to update your API in Azure.
I then check Azure portal and find some error in 'Create API or Update API' json
...
"properties": {
"statusCode": "BadRequest",
"serviceRequestId": "*****",
"statusMessage": "{\"error\":{\"code\":\"ValidationError\",\"message\":\"One or more fields contain incorrect values:\",\"details\":[{\"code\":\"ValidationError\",\"target\":\"representation\",\"message\":\"Parsing error(s): JSON is valid against no schemas from 'oneOf'. Path 'securityDefinitions.Bearer', line 2841, position 15.\"},{\"code\":\"ValidationError\",\"target\":\"representation\",\"message\":\"Parsing error(s): The input OpenAPI file is not valid for the OpenAPI specificate https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md (schema https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json).\"}]}}",
"eventCategory": "Administrative",
"entity": "/subscriptions/*****/resourceGroups/XXX/providers/Microsoft.ApiManagement/service/WebApplicationXXXapi/apis/WebApplicationXXX",
"message": "Microsoft.ApiManagement/service/apis/write",
"hierarchy": "*****"
},
...
So I open the generated swagger.json file from 'C:\Users\YYYY\source\repos\WebApplication_XXX\WebApplication_XXX\bin\Release\netcoreapp3.1\swagger.json' in swagger editor and get the same error:
Structural error at securityDefinitions.Bearer
should have required property 'type'
missingProperty: type
because the Security Definitions Bearer is empty in the json file
securityDefinitions:
Bearer: {
}
if I make the following change in in the swagger editor it gets happy:
securityDefinitions:
Bearer: {
type: apiKey,
name: "JWT Authentication",
in: "header"
}
In my application Startup.cs I got:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "XXX API", Version = "v1" });
var securityScheme = new OpenApiSecurityScheme
{
Name = "JWT Authentication",
Description = "Enter JWT Bearer token **_only_**",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer", // must be lower case
BearerFormat = "JWT",
Reference = new OpenApiReference
{
Id = JwtBearerDefaults.AuthenticationScheme,
Type = ReferenceType.SecurityScheme
}
};
c.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{securityScheme, new string[] { }}
});
});
what is it Im missing? Shouldnt the code in Startup.cs add the securityDefinition when generating the swagger.json file?

We have the same problem. For now we have used a workaround with disabling update the api during publish. (I use VS2022 and .net6.0)
In the PublishProfiles/...pubxml change the parameter UpdateApiOnPublish to false.
<UpdateApiOnPublish>false</UpdateApiOnPublish>

Can you check if there is any target framework missing also check your NuGet packages dependency.
JwtSecurityTokenHandler class which generated a token needs to be implemented. To understand the correct workflow for JWT implementation check this JWT Authentication Tutorial with Example API.

Related

Securing Blazor WASM and API with Auth0. CORS Policy issue

I've been following the tutorial at Auth0 for securing a Blazor WASM and API with Aut0, which is found here --> https://auth0.com/blog/securing-blazor-webassembly-apps/
Securing the app works fine, but adding the API gives me issues. As soon as I add the authenticate attribute to the API Controller it results in this:
fetchdata:1 Access to fetch at
'https://localhost:7226/weatherforecast' from origin
'https://localhost:7298' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource. If an opaque response serves your needs, set the request's
mode to 'no-cors' to fetch the resource with CORS disabled.
I've added a policy to allow the app in the program.cs
builder.Services.AddCors(options =>
{
options.AddPolicy("Open", builder => builder.WithOrigins("https://localhost:7298").AllowAnyMethod().AllowAnyHeader());
});
I've played around with the program.cs and also added app.UseCors before authentication/authorization (as a provided solution I found online), which then results in another issue.
Failed to load resource: the server responded with a status of 401 ()
blazor.webassembly.js:1 crit:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: The input does not contain any JSON tokens. Expected the input to start with a valid JSON
token, when isFinalBlock is true. Path: $ | LineNumber: 0 |
BytePositionInLine: 0. System.Text.Json.JsonException: The input does
not contain any JSON tokens. Expected the input to start with a valid
JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 |
BytePositionInLine: 0.
That error seems to indicate an issue with the bearertoken not being set, but it is setup using BaseAddressAuthorizationMessageHandler.
builder.Services.AddHttpClient("APIClient", client =>
{
client.BaseAddress = new Uri("https://localhost:7226");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
I've added the project to GitHub, if more details on the code is of interest
https://github.com/obrungot/BlazorAuthenticationPlayGround.git
AddCors doesn't actually do anything except for adding a policy. It's not using that policy until you specify it somewhere. You can specify a global policy by using app.UseCors("Open"), add the policy to the endpoint routing e.g. app.MapGet("/test", () => Results.Ok("test")).RequireCors("Open") or for controllers by using an attribute like [EnableCors("Open")].
That you received a 401 suggested that Cors in general seems to work, however Cors also needs explicit permission to keep the Authorization header. This is done by adding "AllowCredentials()" to the policy like this:
builder.Services.AddCors(options =>
{
options.AddPolicy("Open", builder => builder
.WithOrigins("https://localhost:7298")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});
I hope this helps!
Edit:
Sorry. I somehow missed the github repository link. The reason why it doesn't work is that BaseAddressAuthorizationMessageHandler is meant for hosting the API within the BaseAddress of the app. So in your case only calls to https://localhost:7298/ will include the token. You might either choose to host the API together with the app in the same process (this can be set up by choosing "ASP.NET Core Hosted" in the template) or use a custom AuthorizationMessageHandler which you can learn about here https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/additional-scenarios?view=aspnetcore-7.0#custom-authorizationmessagehandler-class
In your case this would look like this:
public class ApiAuthorizationMessageHandler : AuthorizationMessageHandler
{
public ApiAuthorizationMessageHandler(IAccessTokenProvider provider, NavigationManager navigationManager) : base(provider, navigationManager)
{
ConfigureHandler(new[] { "https://localhost:7226" });
}
}
When it comes to the cors the order is important
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
If set up like that "[EnableCors("Open")]" on the controller should work.

Add custom attribute to OpenAPI specification file and swagger in .net core web api

I have a .Net Core 5 Web API project (C#) where I've added and configured Swagger.Net. Everything works fine, but now the client has asked me to add a "custom attribute" in the OAS file to specify that the APIs are not yet ready in production:
x-acme-production-ready=false
As of today I have always provided the json file automatically produced by Swagger.
How can I produce the OAS file with a structure like this:
openapi: "3.0.0"
# REQUIRED - Formal commitments from the API focal point
x-acme-api-commitments:
api-100: We commit to providing a proper valid OpenAPI (swagger) specification file for each API change.....
# REQUIRED - List of versions changes
x-acme-api-changelog:
- version: 1.0.0
changes: Add GET /example
- version: 1.1.0
changes: Add POST /example
info:
# REQUIRED - Functional descriptive name of the API.
title: ACME - Basic template API
The above file looks like is a text representation of the JSON, so maybe should be enough to add the custom field x-acme-production-ready to the JSON, but how can I add it programmatically?
********* UPDATE ***********
Looking at the specification above this custom field should be added at the same level of the tag "info" in the JSON swagger:
openapi: "3.0.1",
x-acme-production-ready: "true",
info: {
title: "my-app-title",
version: "v1.0"
},
servers: [
{
url: "https://localhost:44370"
}
],
paths: {...}
I have added the class CustomModelDocumentFilter to my project, but I can't understand how and where to call it, and how to use it for adding that field in that position.
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
namespace MyApp.Swagger
{
public class CustomModelDocumentFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
swaggerDoc....
}
}
}
In my startup I have:
services.AddSwaggerGen(c =>
{
c.DocumentFilter<Swagger.CustomModelDocumentFilter>();
c.SwaggerDoc("v1.0", new OpenApiInfo { Title = "my app title", Version = "v1.0", Description = "my app description." });
string xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
string xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
});
If you use Swashbuckle.AspNetCore, you can use a document filter to customise the OpenAPI document.

Pass url parameter from Appsettings.json (.core) to React

I am trying to access the url parameter inside the appsettings.json file. The reason is that the api URL differs from Development to publish. I am not entirely sure the best way to solve this.
I've found a solution that could work:
how to get config data from appsettings.json with asp.net core & react
As I've understood from above thread, I need to create a service and call it from React? This seems abit wierd since I always(?) need to do a API request to the same project to recieve the URL which is needed for the API requests.
The other suggestion is to use webpack, or somehow save the url in the clientside. But won't this mean that whenever I need to change environment, I need to change that in 2 places (backend & frontend)?
This is how my appsettings.json file looks (same variable but different values for .Development and .Publish).
{
"Url": "localhost:44000"
}
In my Startup class I am getting the value:
var urlValue =
_configuration.GetSection("Url");
Can't I somehow get the value once depending on environment from the backend and recieve it using React?
Not sure if I am thinking wrong here?
Would appreciate if anyone is able to point me to the right direction.
My solution to this is using .env documents but still using .core launchSettings env.
For this solution to work, I was in need of env-cmd:
npm install env-cmd
Added 3 .env files:
1. .env
2. .env.development
3. .env.prod
Each file contains a url string:
REACT_APP_Url = https://localhost:44000
I added env check in .core startup file:
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
else if (env.IsProduction())
{
spa.UseReactDevelopmentServer(npmScript: "build");
}
});
When I am running production code - I am refering to "build", so in my case the object "build" is going to run.
package.json file:
"scripts": {
"start": "rimraf ./build && react-scripts start",
"build": "cross-env env-cmd -f .env.prod react-scripts start",
}
I can now access the url by using:
{process.env.REACT_APP_Url}

Unable to Load swagger API page, missing swagger-ui.css

I am trying to add swagger to my service, but I am having some problems.
When I go to my page I get multiple calls to my webpage
/swagger/index.html -> Returns 200
/swagger/swagger-ui.css -> Returns 500
/swagger/swagger-ui-bundle.js -> Returns 500
/swagger/swagger-ui-standalone-preset.js -> Returns 500
/swagger/favicon-32x32.png -> Returns 500
/swagger/favicon-16x16.png -> Returns 500
If I go to localhost/api/myServiceName/swagger/v1/swagger.json, the file looks ok. I can see my endpoints and DTOs.
In my code I do the following:
ConfigureServices():
services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new Info { Title = "MyService API", Version = "v1" }); });
Configure():
app.UseSwagger();
app.UseSwaggerUI(
c =>
{
c.SwaggerEndpoint($"/api/MyService/swagger/v1/swagger.json",
"MyService API V1");
});
My project references:
Swashbuckle.AspNetCore 3.0.0
Swashbuckle.AspNetCore.Swagger 3.0.0
Swashbuckle.AspNetCore.SwaggerGen 3.0.0
Swashbuckle.AspNetCore.SwaggerUI 3.0.0
I am pretty sure something is wrong with my configuration. Any idea on what the error is?
Add a reference to Microsoft.AspNetCore.StaticFiles
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/851

How do I specify the "scheme" element using NSwag and C#?

I'm using ASP.NET Core and NSwag to host and describe a new web service hosted in IIS with Windows Authentication.
Locally I run the web service using https, but when I deploy to a test environment the web service sits behind a load balancer with SSL-offloading. This means that even though the site appears to run under SSL in the browser, the actual binding in IIS is http. So my Swagger UI page (and swagger.json definition) describes the schemes supported as http.
I'd like the Schemes element in the Swagger.json that I use to read "https" instead of "http". Would anyone be able to help me find the property I need to set in my code to set the scheme manually?
{
x-generator: "NSwag v11.19.1.0 (NJsonSchema v9.10.72.0 (Newtonsoft.Json v11.0.0.0))",
swagger: "2.0",
info: {
title: "My API title",
description: "Provides access to data.",
version: "1.0.0"
},
host: "myhostname.net",
schemes: [
"http"
],
etc...
}
Boom. Got it!
Finally found an answer on Github and the following code did the trick:
app.UseSwaggerWithApiExplorer(config =>
{
//...other code omitted...
config.PostProcess = settings =>
{
settings.Schemes.Clear();
settings.Schemes.Add(NSwag.SwaggerSchema.Https);
};
});
EDIT:
for NSwag v12 use:
app.UseSwagger(configure => configure.PostProcess = (document, _) => document.Schemes = new[] { SwaggerSchema.Https });
My project was using NSwag v13 and the below worked for me.
app.UseOpenApi(a => {
a.PostProcess = (document, _) => {
document.Schemes = new[] { OpenApiSchema.Https, OpenApiSchema.Http };
};
});
Source:
https://github.com/RicoSuter/NSwag/issues/1545

Categories

Resources