ArgumentNullException for ConnectionString When trying to remotely connect to .net core API - c#

First of all is this happening in a Mac and I'm new to dotnet core.
I have installed dockers and setup everything in dotnet core. I did add connectionstring to the 'appsettings' and 'appsettings(Development)'.
"ConnectionStrings": {
"Default": "server=localhost; database=Monitor; User ID=sa; Password=MyComplexpPassword!234;"
},
This is Program.cs file Main method
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
This is startup.cs class ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
services.AddAutoMapper();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<MonitorDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Default")));
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.AddScoped<IUserRepository,UserRepository>();
}
This is a Controller test method to test API.
[HttpGet("getUser")]
public UserResource GetUserInfo()
{
var user_1 = new User();
user_1.FirstName = "MAC";
user_1.LastName = "OS TEST";
user_1.Username = "Apple#gmail.com";
return mapper.Map<User, UserResource>(user_1);
}
This method will perfectly execute If I make a rest call(http) without setting up Program.cs class for remote access.
Now I have set it up to run in 'http://0.0.0.0:6001', So that I can access the API from my phone or from another pc in the same wifi.
I followed This instructions.
Now My Program.cs main method is like this.
public static void Main(string[] args)
{
// CreateWebHostBuilder(args).Build().Run();
var configuration = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
var hostUrl = configuration["hosturl"];
if (string.IsNullOrEmpty(hostUrl))
hostUrl = "http://0.0.0.0:6000";
var host = new WebHostBuilder()
.UseKestrel()
.UseUrls(hostUrl) // <!-- this
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseConfiguration(configuration)
.Build();
host.Run();
}
In terminal I ran this command dotnet run --hosturl http://0.0.0.0:6001
If try to access same method as before this happens.
Notice:- I changed only the host, Because I need to test the API with other devices.
I have other controllers and methods that are connecting to the database and do crud operations with it, Those API calls also face the same issue like this. This only happens if I set it up to remote access.
Notice:- If I change the Startup.cs class Connection string line like this, It will work flawlessly in both configurations.
services.AddDbContext<MonitorDbContext>(options => options.UseSqlServer("server=localhost; database=Monitor; User ID=sa; Password=MyComplexpPassword!234;"));
But I felt that this is not good practice. In future, I have to add JWT Authentication to the API so that APP_Secret also needed to add to the AppSettings.json file.
Thank you.

you didn't tell the application to use appsettings.json. change below configuration
var configuration = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
To
var configuration = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddCommandLine(args)
.Build();

As an alternative, you can use the static WebHost.CreateDefaultBuilder method which by default loads settings from 'appsettings.json', 'appsettings.[EnvironmentName].json', and command line args.
Note -> As stated here:
AddCommandLine has already been called by CreateDefaultBuilder. If you
need to provide app configuration and still be able to override that
configuration with command-line arguments, call the app's additional
providers in ConfigureAppConfiguration and call AddCommandLine last.
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
// Call other providers here and call AddCommandLine last.
config.AddCommandLine(args);
})
.UseStartup<Startup>();

Related

How to get Args from Provider (c# .NET Core console app)?

I try to make a .NET Core console app with singleton. In main I have:
Configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddCommandLine(args)
.Build();
var services = ConfigureServices();
var serviceProvider = services.BuildServiceProvider();
serviceProvider.GetService<App>().Run();
and in App.cs:
public App(IConfiguration config, IConfigurationRoot configuration)
{
conf = config;
var list = configuration.Providers.ToList();
var provider = (CommandLineConfigurationProvider)list[1];
}
How can I download string[] (or list, or whatever) with arguments from provider?
Answer provided by Martin Costello (from comments):
You can use Environment.GetCommanLineArgs() to get the raw command line to the application. The providers are an abstraction, so don't give you access to exactly what was passed into them.
Link: learn.microsoft.com: GetCommandLineArgs

Appsettings transform in .NetCore not working as expected

I have developed a web API and published it on azurewebsites.net.
I have added the following additional appsettings:-
appsettings.Dev.json
appsettings.Test.json
appsettings.Prod.json
To be able to extract values from these appsettings transforms I made the following code changes:
Tried the solution mentioned here:
https://stackoverflow.com/a/44953524/10485667
Even tried using only the Development/Debug, Staging and Production/Release instead of Dev, Test, Prod receptively. But no luck. It would only publish the values from the main appsettings.json.
Startup.cs
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
#if DEBUG
.AddJsonFile($"appsettings.Dev.json", optional: true)
#endif
.AddEnvironmentVariables();
Configuration = builder.Build();
appSettings = Configuration.Get<AppSettingsModel>().AppSettings;
}
even tried this code:
AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
Tried changing the Program.cs:
public class Program
{
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.AddJsonFile($"appsettings.Development.json", optional: true)
.Build();
ILogger logger = null;
var host = CreateWebHostBuilder(args)
.UseConfiguration(config)
.Build();
logger = host.Services.GetService<ILogger>();
host.Run();
}
}
Tried every possible solution provided on internet but no luck. After publishing to azure, it takes the values only from appsettings.json
I think I might be making some conceptual mistake while attempting these solutions. Any kind of help is appreciated.
Thanks in advance

How can I create and run a webhost inside my test-libary?

I am currently working on a pretty simple test libary. The solution also contains an ASP.NET Core Webhost, which processes simple CRUD operations.
I want to unit test this ASP.NET Core application without always having to start both projects, so I am creating a new WebHostBuilder inside my NUNit test-libary.
[OneTimeSetUp]
public void SetupHost()
{
var webhostBuilder = new WebHostBuilder()
.UseKestrel()
.UseIISIntegration()
.UseContentRoot("root")
.UseStartup(typeof(Startup))
.ConfigureAppConfiguration((builderContext, config) =>
{
config.AddJsonFile("config1", false);
config.AddJsonFile("config2", false);
});
webhostBuilder
.Build()
.Run();
}
The problem is that SetupHost() never finishes, because Run() blocks the thread until the host shuts down.
How can I start a new webhost, then after it successfully started start my unit tests?
Hold on to the IWebHost and use Start instead
IWebHost host;
[OneTimeSetUp]
public void SetupHost() {
var webhostBuilder = new WebHostBuilder()
.UseKestrel()
.UseIISIntegration()
.UseContentRoot("root")
.UseStartup(typeof(Startup))
.ConfigureAppConfiguration((builderContext, config) =>
{
config.AddJsonFile("config1", false);
config.AddJsonFile("config2", false);
});
host = webhostBuilder.Build();
host.Start(); //Starts listening on the configured addresses.
}
Later, call StopAsync to attempt to gracefully shut down the host.

Why do I get ERR_EMPTY_RESPONSE running nopCommerce 4 in Visual Studio with SSL?

When I try to run nopCommerce 4.0 locally in VisualStudio with SSL, I get the error ERR_EMPTY_RESPONSE. Running without HTTPS works fine. I am testing integration with an external login and I need to run HTTPS locally to avoid mixed content problems.
I know there are several SO posts about this, but they all lead me to the same place. My latest attempt is based on this article.
In my Startup.cs, I have:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc(
options =>
{
options.SslPort = 55391;
options.Filters.Add(new RequireHttpsAttribute());
}
);
services.AddAntiforgery(
options =>
{
options.Cookie.Name = "_af";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.HeaderName = "X-XSRF-TOKEN";
}
);
return services.ConfigureApplicationServices(Configuration);
}
In certificate.json, I have:
{
"certificateSettings": {
"filename": "localhost.pfx",
"password": "secretpassword"
}
}
In Program.cs, I have:
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddEnvironmentVariables()
.AddJsonFile("certificate.json", optional: true, reloadOnChange: true)
.AddJsonFile($"certificate.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true)
.Build();
var certificateSettings = config.GetSection("certificateSettings");
string certificateFileName = certificateSettings.GetValue<string>("filename");
string certificatePassword = certificateSettings.GetValue<string>("password");
var certificate = new X509Certificate2(certificateFileName, certificatePassword);
var host = WebHost.CreateDefaultBuilder(args)
.UseKestrel(options =>
{
options.AddServerHeader = false;
options.Listen(IPAddress.Loopback, 55391, listenOptions =>
{
listenOptions.UseHttps(certificate);
});
options.Listen(IPAddress.Loopback, 55390);
})
.UseStartup<Startup>()
.CaptureStartupErrors(true)
.Build();
host.Run();
}
I have ASPNETCORE_HTTPS_PORT set to 55391 in my Nop.Web project settings.
When I run this, I get the error ERR_EMPTY_RESPONSE.
If I remove all of the HTTPS options and just go with the standard setup, everything works fine.
Edit: I have to run this project with the Nop.Web profile, so I can't run it with IIS Express and just get the SSL settings in the project properties.
Edit #2: I noticed that when I get this error, the browser is being redirected from https://localhost:55391 to http://localhost:55391 (no s). I'm not sure why.

ASP.NET Core web service does not load appsettings.json into configuration

I have an ASP.NET Core 2.1 Web Application with Razor Pages which has AAD authentication information defined in the appsettings.json file (courtesy of the default application template - see below on how I got there). However, when trying to configure the authentication in Startup.cs the configuration does not have any of the config values from my appsettings.json. If I inspect the IConfiguration object in the debugger then it appears to only have the environment variable configurations:
Here's the Startup.ConfigureServices method where the issue lies:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options =>
{
// This is from the default template. It should work, but the relevant settings aren't there so options isn't populated.
this.Configuration.Bind("AzureAd", options);
// This of course works fine
options.Instance = "MyInstance";
options.Domain = "MyDomain";
options.TenantId = "MyTenantId";
options.ClientId = "MyClientId";
options.CallbackPath = "MyCallbackPath";
});
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
And the service configuration in case it's important (note that this is being built on top of a service fabric stateless service):
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new ServiceInstanceListener[]
{
new ServiceInstanceListener(serviceContext =>
new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
{
ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");
return new WebHostBuilder()
.UseKestrel(opt =>
{
int port = serviceContext.CodePackageActivationContext.GetEndpoint("ServiceEndpoint").Port;
opt.Listen(IPAddress.IPv6Any, port, listenOptions =>
{
listenOptions.UseHttps(GetCertificateFromStore());
listenOptions.NoDelay = true;
});
})
.ConfigureServices(
services => services
.AddSingleton<StatelessServiceContext>(serviceContext))
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseUrls(url)
.Build();
}))
};
}
To create this service, I used the wizard in VS2017. I selected an existing service fabric project (.sfproj) and chose Services > Add > New Service Fabric Service and chose Stateless ASP.NET Core [for .NET Framework], then on the next page I chose Web Application (the one with Razor Pages, not MVC) and clicked Change Authentication where I chose Work or School Accounts and entered my AAD info. The only changes I have made to this template were adding the code inside the call to AddAzureAD in Startup.ConfigureServices and setting the appsettings.json files to always be copied to the output directory.
Why doesn't the appsettings.json file get loaded into the configuration? As I understand, this is supposed to happen by default, but something seems to be missing...
WebHostBuilder doesn't load appsettings.json by default, you need to manually call AddJsonFile. For example:
return new WebHostBuilder()
.UseKestrel(opt =>
{
//snip
})
.ConfigureAppConfiguration((builderContext, config) =>
{
config.AddJsonFile("appsettings.json", optional: false);
})
.ConfigureServices(
services => services
.AddSingleton<StatelessServiceContext>(serviceContext))
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseUrls(url)
.Build();
Alternatively you can use WebHost.CreateDefaultBuilder which will load more defaults.
Another approach, would be to manually create the configuration via ConfigurationBuilder then use the UseConfiguration method.
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true)
.Build();
var host = new WebHostBuilder()
.UseConfiguration(configuration)
.UseKestrel()
.UseStartup<Startup>();
The primary intent is core to provide a bit of flexibility when implementing, they often error on less is more. You have to explicitly say what you would like, that way the pipeline remains relatively small.
For others like me who find this issue:
It might be that you're not copying the appsettings.json file during build.
The OP does say he's doing this, but it's kind of a small print thing - and was what I was failing to do.
The more you know ...
Below mentioned steps worked for me
Go to Appsettings.json
Right click and goto properties
select the build action from the drop down to none if its content
Make the copy to Output directory as Copy Always
As mentioned before WebHostBuilder do not execute this default behavior CreateDefaultBuilder needs to be called instead.
I prefer following implementation:
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
var logger = host.Services.GetRequiredService<ILogger<Program>>();
try
{
logger.LogInformation("Starting up");
host.Run();
}
catch (Exception ex)
{
logger.LogCritical(ex, "Application start-up failed");
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Make sure your file name is all lower case.
My mistake was to name the file appSettings.json instead of appsettings.json. When running within a Linux container, the camel-cased file was not loaded.

Categories

Resources