I've written a C# class library for my company to use internally, and it uses DotNet UserSecrets to allow each developer to have their own credentials set without needing to worry about accidentally committing them. It worked fine during testing, but after installing it as a NuGet package as opposed to a project dependency, it no longer seems to be able to read from the secrets.json file. I'm wondering if this is a security thing that C# prevents, or if I need to do something else to enable that functionality in an external package.
The package code looks like this:
using Microsoft.Extensions.Configuration;
using TechTalk.Specflow;
namespace Testing.Utilities
{
[Binding]
public class Context
{
private static IConfigurationRoot configuration { get; set; }
private static FeatureContext feature_context;
// SpecFlow attribute runs this before anything else executes
[BeforeFeature(Order = 1)]
private static void SetFeatureContext(FeatureContext context)
{
try
{
configuration = new ConfigurationBuilder()
.AddUserSecrets<Context>()
.Build();
}
catch { }
feature_context = context;
test_context = context.FeatureContainer.Resolve<TestContext>();
}
public static string GetSecretVariable(string name)
{
object v = null;
// if the user secrets were found
if (configuration != null)
{
v = configuration[name];
}
if (v == null)
{
Logger.Warning($"secret variable '{name}' not found");
return null;
}
return v.ToString();
}
}
}
And in the calling code which always gets Null from the getter method:
using Testing.Utilities; // via NuGet package
namespace Testing
{
public static void Main()
{
System.Console.WriteLine($"found {Context.GetSecretVariable("super_secret")}");
}
}
Update:
It works as expected when I drag my locally built .nupkg file into my NuGet package cache and replace the one pulled from the repo. I updated the version number and pushed the change so I know they are on the same version, and it still only worked when I manually inserted my build. Now I'm more confused...
I ported the project from .NET Framework 4.6.1 to .NET 6 and it seemed to fix it. Kinda drastic change, but easy enough refactor and 461 is EOL anyways.
Related
I have a DLL MyAssemblyOne.dll which only contains one class with static methods:
namespace MyAssemblyOne
{
public class MyClassOne
{
public static string MyStaticMethod()
{
...
}
}
}
All is good so far, the assembly MyAssemblyOne.dll is generated.
Now I have another DLL, MyAssemblyTwo.dll which has a dependency on MyAssemblyOne.dll and uses it like:
no using here;
namespace MyAssemblyTwo
{
public class MyClassFromAssemblyTwo
{
public string SomeRandomMethod()
{
...
var smth = MyAssemblyOne.MyClassOne.MyStaticMethod();
...
}
}
}
Now I create a Xamarin project with Linking set to Sdk Assemblies Only and Use Shared Runtime disabled(basically Release mode), and I add my two DLLs - MyAssemblyTwo.dll and MyAssemblyOne.dll. The app builds ok, but when I run it I get something like:
cannot find MyAssemblyOne.dll.
Please note that this works if the Linking option is set to None.
However, if I change MyAssemblyTwo usage of MyAssemblyOne to be:
using MyAssemblyOne;
namespace MyAssemblyTwo
{
public class MyClassFromAssemblyTwo
{
public string SomeRandomMethod()
{
...
var smth = MyClassOne.MyStaticMethod();
...
}
}
}
everything works fine even with the Linking set to Sdk Assemblies Only.
How does the linker work? Why if I have a using statement everything is fine, but if I use the assembly name directly in the code it breaks.
It is worth mentioning that MyAssemblyOne and MyAsseblyTwo are .netstandard20 projects.
I have some code in my ConfigureServices that fails when running a migration:
dotnet ef migrations list
I'm trying to add a Certificate but it can't find the file (it works when starting the project as a whole). So is there a way to do something like this:
if (!CurrentEnvironment.IsMigration()) {
doMyStuffThatFailsInMigration()
}
That way I could keep my code as it is but just execute it when not running it in a migration.
Thanks
Just set a static flag in the Main method (which is not called by the dotnet-ef tool):
public class Program
{
public static bool IsStartedWithMain { get; private set; }
public static void Main(string[] args)
{
IsStartedWithMain = true;
...
}
}
and then check it when needed:
internal static void ConfigureServices(WebHostBuilderContext context, IServiceCollection services)
{
if (Program.IsStartedWithMain)
{
// do stuff which must not be run upon using the dotnet-ef tool
}
}
EDIT: in Dotnet 6.0 there's no separate ConfigureServices method. Everything is initialized in the Main method (can be created with dotnet new .. --use-program-main). In this case a flag can be used for skipping EF stuff:
private static bool IsStartedWithMain =>
Assembly.GetEntryAssembly() == Assembly.GetExecutingAssembly();
My current solution to detecting if a migration has not occurred:
using System.Linq;
// app is of type IApplicationBuilder
// RegisteredDBContext is the DBContext I have dependency injected
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var context = serviceScope.ServiceProvider.GetService<RegisteredDBContext>();
if (context.Database.GetPendingMigrations().Any())
{
var msg = "There are pending migrations application will not start. Make sure migrations are ran.";
throw new InvalidProgramException(msg);
// Instead of error throwing, other code could happen
}
}
This assumes that the migrations have been synced to the database already. If only EnsureDatabase has been called, then this approach does not work, because the migrations are all still pending.
There are other method options on the context.Database. GetMigrations and GetAppliedMigrations.
I'm using Squirrel.Windows as an update framework for my application and I upgraded from 1.4.4 to the latest version 1.5.2 and after upgrading via NuGet the UpdateManager class became inaccessible due to it's protection level.
I created a sample project and imported the Squirrel.Windows nuget package via NuGet and I was able to instantiate an instance of the UpdateManager class without issue.
I tried cleaning out all the NuGet packages related to the Squirrel.Windows project and cleaned up any information remaining in the csproj that was related to it, after importing the package again I was still unable to access the class.
namespace Our.Core
{
public class Launcher
{
public static void Main(string[] args)
{
new Launcher(args);
}
public async Task<bool> TryUpdate(string[] args)
{
try
{
using (var mgr = new UpdateManager(UpdatePath, null, null, null))
{
Log.Information("Checking for updates");
var updateInfo = await mgr.CheckForUpdate();
if (updateInfo.ReleasesToApply.Any())
{
Log.Information("Downloading updates");
await mgr.DownloadReleases(updateInfo.ReleasesToApply);
Log.Information("Applying updates");
await mgr.ApplyReleases(updateInfo);
return true;
}
Log.Information("No updates found.");
return false;
}
}
catch (Exception e)
{
Log.Error(e, "Error while updating");
return false;
}
}
}
}
The problem turned out to be that after upgrading the library, the reference in the project had its Specific Version property toggled to false. This caused Visual Studio to be unable to correctly reference the correct version of the library.
Moral of the story, make sure to check your version and that your specific version check is true if you need to use a specific version!
I'm trying to run some javascript from a .NET class library using JSPool and JavaScriptEngineSwitcher.V8, but I can't work out how to install JavaScriptEngineSwitcher.V8. My code so far is simple
public class Renderer : IDisposable
{
private readonly JsPool _pool;
private static readonly string[] _requiredFiles = { "vendors", "app" };
public Renderer(string jsPath)
{
_pool = new JsPool(new JsPoolConfig
{
Initializer = initEngine =>
{
foreach (var file in _requiredFiles)
{
initEngine.ExecuteFile(jsPath + "\\" + file + ".js");
}
}
});
}
public string Render()
{
using (var engine = _pool.GetEngine())
{
return engine.Evaluate<string>(#"myjsFn()");
}
}
public void Dispose()
{
_pool.Dispose();
}
}
But this throws a NullRefException as no engine has been registered
NullReferenceException: Object reference not set to an instance of an object.
JavaScriptEngineSwitcher.Core.JsEngineSwitcher.CreateDefaultJsEngineInstance()
My app is targeting dnx451, and I've specified JSPool 0.4.1 and JavaScriptEngineSwitcher.V8 1.5.8 in my dependencies. I've had a good look but can't seem to find anything that shows any code required to register the V8 engine. Can anyone point me in the right direction?
This problem was solved in the JavaScript Engine Switcher version 2.0.0 and JSPool version 2.0.0. Before installing of NuGet packages, I recommend to first read “How to upgrade applications to version 2.X” section of the documentation.
But worth noting, that the JavaScriptEngineSwitcher.V8 module can be used only in web application created by the “ASP.NET Core Web Application (.NET Framework)” template.
In my package I am using (DTE) GetService(typeof (DTE)) to get information about the currently opened solution. Is there a way to simulate this for a test, particularly so that I can build using dte.Solution.SolutionBuild?
Code in main package class:
var solutionModel = new SolutionModel(((DTE) GetService(typeof (DTE))).Solution);
SolutionModel class (stripped back):
public class SolutionModel
{
private readonly Solution _packageSolution;
public SolutionModel(Solution solution)
{
_packageSolution = solution;
}
public SolutionModel() {} // This constructor is used for tests so _packageSolution will be null
public bool Build()
{
if (_packageSolution != null)
{
var buildObject = _packageSolution.SolutionBuild;
buildObject.Build(true);
return buildObject.LastBuildInfo == 0;
}
return ManualCleanAndBuild(); // current messy alternative way of doing the build for tests
}
}
So I want to be able to use the _packageSolution build rather than ManualCleanAndBuild() in my tests.
Assuming that you are referring to integration tests (and not to unit tests) where you need to load your package in a real Visual Studio instance, it depends on the testing framework that you are using. If you are using MSTest with the VSIDE Host Adapter (the integration test project that the package wizard creates if you mark the checkbox in the last page of the wizard) there is a Utils.cs file that uses the static VsIdeTestHostContext class to get the DTE instance or services:
public static class VsIdeTestHostContext
{
[CLSCompliant(false)]
public static DTE Dte { get; }
public static IServiceProvider ServiceProvider { get; set; }
}
If you want to learn the inners of the VS IDE Host Adapter I think that the VS 2008 SDK was the last SDK that provided the source code and the documentation (http://msdn.microsoft.com/en-us/library/bb286982%28v=vs.90%29.aspx)
The way I ended up 'solving' this was to mock EnvDTE.Solution instead (seems like it can only be done in the Package_IntegrationTests project which is created for you - you can't reference EnvDTE in any other project). I couldn't figure out how to use the methods in Utils.cs as suggested by Carlos below to open my existing solutions.