Environment.GetEnvironmentVariable return null in Function App when debugging - asp.net-core

I am debugging an Azure function app today and would have run the app at least 20 times with no issues at all with Environment.GetEnvironmentVariable("DCConnection") working perfectly (it returns the connection string to the db). I then added a new function app to the solution and set it up the same as the first one (.Net 6.0, isolated). When running this new function app the Environment.GetEnvironmentVariable fails and returns null.
What? Much checking later, the local.settings.json is there in the project and gets copied to the bin folder. The one in the bin folder is actually the correct once (copied from the project). Grr!
I then went back to the first project and now it won't work either. Cleaned the whole solution, deleted all the bin and obj folders, did a "dotnet restore -f", rebuilt everything - still no go!
Then I thought I would reboot the pc, still no luck. I am currently at a loss as what to do as Environment.GetEnvironmentVariable always returns null when debugging. Next will be hard coding the connection string in the app just to get the debugging running again.
When deploying the function app to Azure, everything works fine and the connection is returned and all is good.
Any ideas?
Out of interest here is the first section of the program.cs for this function app (which has been working earlier today):
public class Program
{
public static async Task Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
services.AddHttpContextAccessor();
var connectionString = Environment.GetEnvironmentVariable("DCConnection");

Related

Can I determine `IsDevelopment` from `IWebJobsBuilder`

Very much an XY problem, but I'm interested in the underlying answer too.
See bottom for XY context.
I'm in a .NET Core 3 AzureFunctions (v3) App project.
This code makes my question fairly clear, I think:
namespace MyProj.Functions
{
internal class CustomStartup : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
var isDevelopment = true; //Can I correctly populate this, such that it's true only for local Dev?
if(isDevelopment)
{
// Do stuff I wouldn't want to do in Prod, or on CI...
}
}
}
}
XY Context:
I have set up Swagger/Swashbuckle for my Function, and ideally I want it to auto-open the swagger page when I start the Function, locally.
On an API project this is trivial to do in Project Properties, but a Functions csproj doesn't have the option to start a web page "onDebug"; that whole page of project Properties is greyed out.
The above is the context in which I'm calling builder.AddSwashBuckle(Assembly.GetExecutingAssembly()); and I've added a call to Diagnostics.Process to start a webpage during Startup. This works just fine for me.
I've currently got that behind a [Conditional("DEBUG")] flag, but I'd like it to be more constrained if possible. Definitely open to other solutions, but I haven't been able to find any so ...
While I am not completely sure that it is possible in azure functions I think that setting the ASPNETCORE_ENVIRONMENT application setting as described in https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings should allow you to get whether the environment is set as production or development by injecting a IHostEnvironment dependency and checking
.IsDevelopment()
on the injected dependency.

How to use Miniprofiler storage to support multiple web instances?

I've hooked up Miniprofiler to my local ASP.NET Core project and it works as expected. Now I need it to work in a hosted environment where there are multiple instances of the same website and there are no sticky sessions. It is my understanding that this should be supported if you just set the storage option when configuring the profiler. However, setting the storage does not seem to do anything. I initialize the storage like this:
var redisConnection = "...";
MiniProfiler.DefaultOptions.Storage = new RedisStorage(redisConnection);
app.UseMiniProfiler();
After doing this, I expected that I could open a profiled page and a result would be added to my redis cache. I would then also expect that a new instance of my website would list the original profiling result. However, nothing is written to the cache when generating new profile results.
To test the connection, I tried manually saving a profiler instance (storage.Save()) and it gets saved to the storage. But again, the saved result is not loaded when showing profiler results (and regardless, none of the examples I've seen requires you to do this). I have a feeling that I've missed some point about how the storage is supposed to work.
It turns out that my assumption that MiniProfiler.DefaultOptions.Storage would be used was wrong. After changing my setup code to the following, it works.
// Startup.cs ConfigureServices
var redisConnection = "...";
services.AddMiniProfiler(o =>
{
o.RouteBasePath = "/profiler";
o.Storage = new RedisStorage(redisConnection); // This is new
});
// Startup.cs Configure
app.UseMiniProfiler();

MVC4 Getting Migrations to Run when publishing app through visual studio 2012

I created a visual studio 2012 MVC4 App. I am testing the "publish" functionality by right clicking the project and choosing publish. I followed the instructions here. I can connect to the remote web server and the folders get published to the correct folder, except the content folder for some reason.
When I run browse to the remote web server it prompts me for login so the app is working. However, the migrations never happened. The only tables created are the simplemembership tables, so I know the web server is connecting to the remote db server. No other tables are created and the seed method doesn't run. I seed the roles and a default user.
I checked the box in publish settings that says "Execute Code First Migrations (runs on application start)"
Everything works fine on my localdb connection string for local testing. Just can't figure out how to create db from existing migrations and seed when I publish to live site, note I will only seed once. Is there a way to specify which migrations to run again? I can copy the migrations and run on the database server but why the extra step?
EDIT:
When adding the database.setinilizer to my context I now get an error saying some of my fields in my userprofile table are not there, I use simple membership. This error occurs on the first page load after web publish, then on proceeding page loads I get an error The "WebSecurity.InitializeDatabaseConnection" method can be called only once.
HOwever, it does create my simplemembership tables now but my migration for all other tables never runs, that is why I am missing the additional user profile fields.
EDIT:
Basically I am not checking if websecurity is initialized prior to calling WebSecurity.InitializeDatabaseConnection so that resolved that issue. Now I have it partially working. The app creates the simplemembership tables fine but since I added tables to the UserProfile table I can't seed until I change them. So instead I manually create the userprofile table and have the app create the rest of the tables. Then I comment out the userprofile table in my initial migration. After this when I sign in it will then create the rest of my tables.
Open issue is how to get my database migration to run prior to the simplemembership initialization?
To get migration work on remote server, you need to add use SetInitializer in you Context class first :
static MyDatabaseContext()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyProjectContext, Migrations.Configuration>());
}
And in you Migration Configuration you need to add this code :
public Configuration()
{
AutomaticMigrationsEnabled = false;
AutomaticMigrationDataLossAllowed = false;
}
I don't select the "Execute Code First Migrations (runs on application start)", and just after setting initialization in MyProjectContext, it does the migration for me.
If you have done by here, for seed your data, you can do same as below in your Migration configuration class:
protected override void Seed(MyProject.Models.MyProjectContextcontext)
{
DoSeed(context);
}
private void DoSeed(MyProjectContext context)
{
var users = new List<User>
{
new Site { UserId = 1, Name = "TestUser", IsDeleted = false },
new Site { UserId = 2, Name = "TestUser2", IsDeleted = false }
};
users.ForEach(s => context.Users.AddOrUpdate(s));
context.SaveChanges();
}
I have not selected the "Execute Code First Migrations (runs on application start)" on deploy Profile.
For some more details on this see this:
This link
and
This link
Hope this helps(as it worked for me), otherwise please add any error if there is, when you deploy you app.
I think the issue is ,Because of the fact that as long as you have not tried to access data
or create any data from/in site, which needs to connect to database, the migration and seeding
will not run"
And the reason for running migration on your site after logging into the site,
would be because your site need to be authorised in all pages, or the page that you want
to see data in.
If you have a page example home page, that does not authorization to access to the page,
you will see the page and if in this page there is some data that needs to be fetched from
data base, you may see the migration runs.
I found this from this Deploy it to IIS, but not sure if it is the reason.
Please let me know if your migration still has not ran if you browse your home page that
has data and no authentication needed for this data access.

Object already exists exception in RSACryptoServiceProvider

First let me start by saying I'm sorry if I posted this question in the wrong place. I saw the entry at Object already exists in RSACryptoServiceProvider. I tried the solutions offered there. But, they did not solve my issue. Also, I didn't see an option to re-ask the question.
I have almost the same issue. I have a class that uses RSACryptoServiceProvider that runs in two projects on the same machine and under the same account. Both projects live in the same solution and share the same encryption code. One project, the server, is a Windows service and the other, the client, is a Windows application. They use the RSACryptoServiceProvider to talk to each other over a named pipe using asymmetric encryption. I started out by just having the server run in another Windows form within the same application as the client. Everything ran fine. Then, I moved the server to a Windows service.
The Windows service starts up fine. It seems to be able to create it's instance of the RSACryptoServiceProvider fine. But, when the client, which runs in the Windows application, starts up it gets a runtime error when it tries to create it. Here is the code that runs in both projects.
rule = New CryptoKeyAccessRule("everyone", CryptoKeyRights.FullControl, AccessControlType.Allow)
csp = New CspParameters
csp.KeyContainerName = _KeyContainerName
csp.Flags = CspProviderFlags.UseMachineKeyStore
csp.CryptoKeySecurity = New CryptoKeySecurity()
csp.CryptoKeySecurity.SetAccessRule(rule)
//Object already exists exception happens here
rsa = New RSACryptoServiceProvider(_KeySize, csp)
As you can see, I have the code that sets the access rule as mentioned in the other post on this subject. Unfortunately, this did not solve my issue. Is there anything else that needs to change?

Triggering EF migration at application startup by code

Using Entity Framework Migrations (Beta1), using Update-Database command is all good during development.
But when the application is running on some customer's server somewhere, I really want my application to automatically update it's database schema to the latest version when it's started.
Is this possible? Documentation is scarce.
They aren't providing a way to do this until RTM, at which point they have promised a command line app and a msdeploy provider.
Source: http://blogs.msdn.com/b/adonet/archive/2011/11/29/code-first-migrations-beta-1-released.aspx
Of course not being satisfied with that, the powershell command is stored in the packages directory and is plain text, it appears to just load up an assembly called EntityFramework.Migrations.Commands stored in the same directory.
Tracing through that assembly I came up with the following
public class MyContext : DbContext
{
static MyContext()
{
DbMigrationsConfiguration configuration = new DbMigrationsConfiguration() {
MigrationsAssembly = typeof(MyContext).Assembly,
ContextType = typeof(MyContext),
AutomaticMigrationsEnabled = true,
};
DbMigrator dbMigrator = new DbMigrator(configuration);
dbMigrator.Update(null);
}
}
UPDATE: after a bit of experimentation I figured out a few more things
Performing an update in the static constructor for your context is bad as it breaks the powershell commands, much better off adding the code to application startup another way (Global.asax, WebActivator or Main method)
The above code only works when using AutomaticMigrations, you need to set the MigrationsNamespace for it to pickup on manually created migrations
The configuration class I was creating should already exist in your project (added when you install the migration nuget package), so just instantiate that instead.
Which means the code is simplified to
DbMigrator dbMigrator = new DbMigrator(new NAMESPACE.TO.MIGRATIONS.Configuration());
dbMigrator.Update(null);
Another options for this issue is to add
Database.SetInitializer<MyContext>(new MigrateDatabaseToLatestVersion<MyContext, NAMESPACE.TO.MIGRATIONS.Configuration>());
line to your Global.asax Application_Start method.