Appsettings.json get string with two programs running - c#

I'm using run and debugging from VS Code, but when i run both projects API and MVC, give me error.
An exception of type 'System.ArgumentNullException' occurred in Microsoft.EntityFrameworkCore.SqlServer.dll but was not handled in user code: 'Value cannot be null.'
My code:
options.UseSqlServer(Configuration["Data:UCASAppDatabase:ConnectionString"]));
This happen after i run both projects using debug, but if i create appsettings outside API work, but what i want is work with appsettings inside API.
How i get string from appsettings.json, without creating new appsettings.json?

It's generally best to keep them separate, but if you really want to use just one, you should be able to add the appsettings.json file as a linked item in the project that doesn't contain the physical file. Use add => existing item, select "Add as Link" from the Add drop-down and select the file(s) you want to add. Make sure their build action is Content + "Copy if Newer" and you should be good to go. You might consider making a solution folder and putting shared resources there so it's more apparent that you have shared resources.
Edit:
You should be able to manually add if VS Code doesn't have a way through the UI.
Editing the .csproj file and add the content files you need:
<ItemGroup>
<Content Include="..\Root\appsettings.json" Link="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

Related

Can I include a resource like an image in an azure function app?

I have an azure function that has a Queue trigger. In the trigger I create a pdf. This pdf should contain a couple of images. How do I include these images in an azure function so that they can be accessed from the code?
My previous version of the code was implemented as a webjob and here we accessed the image like this:
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images", "My_Image.png"
This does not seem to work in my azure function as this path no longer contains my image. The image has build action "None" and is set to "Copy always".
Would be great if someone could point me in the right direction.
There are a number of ways forward here:
You could use Blob Storage to contain your image. You can open that programmatically and get a stream, url, etc.
It might be possible to proceed with your current plan although it seems a little more fraught than I would expect: Including a file when I publish my Azure function in Visual Studio
You could possibly convert the image to base64 and include it in code.
There is a much easier way depending on your CI/CD pipeline to not have to put few files into a separate blob container. In my case, I just needed to include ONE font (ttf) file as my azure function was generating a pdf.
Note: DI will make things easier if you choose to follow this method.
Create a folder called 'Resources' (not necessary but keeps the project clean), and add your file in it. Right-click properties and select 'Copy if Newer'.
Next if you're using the Azure DevOps, add this to your .csproj -
<Target Name="CopyRequiredResources" AfterTargets="_FunctionsPostPublish">
<ItemGroup>
<ResourcesToCopy Include="$(ProjectDir)Resources\*.*" />
</ItemGroup>
<Copy SourceFiles="#(ResourcesToCopy)" DestinationFolder="$(PublishDir)bin" />
</Target>
If you're publishing directly from Visual Studio, then change DestinationFolder to "$(TargetDir)bin".
Edit: Above mentioned destination folders, could be the other way around. It's been a while. Try out both. Best way is to publish to ZIP files and check if the bin folder has the required files. In the case of DevOps, check the bin of the created artifacts. And make the necessary changes to the DestinationFolder.
Basically moving all the required files to the bin folder to keep things easy. The above will work for Azure Function, now to also make sure that the files exists in the same path for local development as well, add the following -
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<ItemGroup>
<ResourcesToCopy Include="$(ProjectDir)Resources\*.*" />
</ItemGroup>
<Copy SourceFiles="#(ResourcesToCopy)" DestinationFolder="$(TargetDir)bin" />
</Target>
In the above bits of MSBuild actions, you're moving your required resources to the publish/bin folder.
now in my pdf writer i had to inject the execution context to get the running app directory -
public class PdfWriter
{
string resourceLoc;
public PdfWriter(IOptions<ExecutionContextOptions> contextOptions)
{
resourceLoc = Path.Combine(contextOptions.Value.AppDirectory, "bin");
}
// img would be in Path.Combine(resourceLoc, "img.jpg");
}
Why I like this method better than the rest -
Dont require a separate blob container just for 1-2 files.
If you decide to change the img or your resource, you dont need to re-do the Base64 conversions. You just replace and republish.
Its all contained within the app itself and has no outside dependency (this ties back to point 1), and hence if you decide to revisit the code in the future, it'll run out of the box.
Makes things easy for collaboration etc. As your team is not reliant on keeping their local blob storage with the required files for things to work.
Further to point 4, I would use this method even if I had several resources. Function code is anyways kept in Azure Storage, so might as well ensure your resources are kept with your code neatly packaged.

VS/C# Equivalent of Java/Eclipse "resource folder"?

While using Java in Eclipse IDE, one can add a folder to the "Build Path" using the "Add Class Folder" option in the "Libraries" tab, which allows the resources in that folder to get compiled inside the application's jar file, rather than outside or not at all.
.
With this, one can get the resources inside the folder as a URL via the Class.getResource(String name)method. I am already informed about C#'s equivalent: Assembly.GetManifestResourceStream(string name) or Assembly.GetManifestResourceInfo(string resourceName) methods, but I am not aware of C#'s "Build Path" equivalence in Visual Studio (I am using 2019, if you wished to know). Could somebody please explain how I would accomplish Java's build path resource folder in C#?
(Note that I am looking to create a resource folder where anything put inside the folder would be considered an application resource. I am not looking for a way to add one or more resource files individually.)
Any replies would be greatly appreciated! :)
After a little research, I had found a solution for this problem. There are in fact two possible solutions to this issue.
.NET Core Solution
The first involves editing the .csproj file of your C# project. This solution is only available in .Net Core.
You can add this code snippet to your file and change the {PATH_TO_RESOUCE_FOLDER_HERE} folder to your desired folder.
<ItemGroup>
<EmbeddedResource Include="{PATH_TO_RESOUCE_FOLDER_HERE}\**" />
</ItemGroup>
Now any item placed in that folder will be considered an embedded resource Assembly.GetManifestResourceStream(string name) method.
Regular .NET Solution
The second method involves using a .resx file to encapsulate all of your resources
In Visual Studio 2019, you can create a .resx file by right clicking on the location in your project where you wish to add the file to, and navigating to Add > New Item (you may also press Ctrl+Shift+A). You can now navigate to the item that quotes "Resources File" and select it. You can now use this GUI to insert your resources (for a deeper explanation, click on this or this link. For use cases, see this MSDN).
The "Resources File" option
Note that this solution will also work in .NET Core.
I hope this answer helped you as much as it did me! :)
You just create a folder and name it as you like it, say 'Resources'. Add any file you want in there to be treated as a resource by your application.
Then navigate to the properties of every resource file (you can press F4) and in the menu you can choose what you want the compiler do with that file (Compile Action is the option name if I remember well). There you select the type as a resource, the namespace (your Build Path), and whether you like the file to be copied every time you compile your application, and so on.

Visual Studio not Copying Directory of Linked Files

A common practice when staging unmanaged libraries or resources is to add those resources as links to the project and set them to copy to the output directory.
As of Visual Studio 2013, this is handled quite well and even if they are referenced Library Foo which is then consumed by Application Bar, they will end up in Bar's output directory.
The same doesn't appear to be true for directories of files though.
In this case, my application appears to only copy this directory of files to the output directory on rebuild only. Then inevitably I'll do a couple build actions and I'll notice the Libs directory is empty again. Then do a Rebuild and cef.pak is back.
My solution to this was to employ a Build Step to copy the Libs directory manually to the output directory. Though I cannot find the proper macro to generically express that even though this build step is part of Foo, I want the files copied to the Bar's (e.g. StartUp Project in VS terms) output directory.
Update
Thank you everyone for the great answers and testing this. I should clarify that I still see this issue when there is an extra level of library in between. That is to say Application Bar referencing library Foo which references library Other which is the one w/ these linked files. In that case, when Other's linked files are set to copy to output directory, they seem to only make it on rebuilds. My solution to this is less than ideal which is to have Foo reference Other directly.
unless you rebuild/clean solution, VS does remove files from output folder.
so i believe you forgot to say that your program(or third party) does so.
First: this is an example for similar/exact bug.
download the solution and do the following steps:
rebuild the solution
open the output folder of Bar
the file cef.pak will be exist in Libs
press F5 -> execute Bar -> everything alright
execute again with F5 -> you will receive an file not found exception
if you repeat steps 1-5 you will receive the same behavior
The issue exist only if there is no changes in Bar and something(the exe / other process/etc) has deleted the file.
Second: I've already faced this issue.
when one of my team member reported this issue, then the answer he received was a kind of "it's not a bug it's a feature"....
As i know, there is no "magic button" to solve for this problem.
But there are several workarounds:
(as you did) adding pre/post build events. I recommend you to do this in new build configuration.
change the build output folder of Foo to Bar output folder.
add in your code a path replacement with if debug:
#if DEBUG
cefFilePath = <build output of foo>
#endif
put the file as embedded resource then extract it.
create an extension\external program to deal with this problem. each project the file keep the information about those file:
<ItemGroup>
<None Include="Libs\cef.pak">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
the application/plugin will do the job for you.
I can offer more solutions/workarounds, but I believe that you did the right thing -> build event.
edit:
I updated my example in the link. now the solution contains 3 workarounds example.
Tried doing same with VS2013. It worked quite well, everytime I change something in Bar's File, Run Foo (Startup Project), the latest file is copied there. I am just writing steps I followed, may be I am missing something to replicate or you missed a step. Please have a look:
Create two Projects Foo and Bar
Created a directory Libs in Bar
Added a text file "TextFile1.txt" in Libs
Right Click -> Properties of the file -> Copy to Output Directory = Copy Always
Added reference of Bar from Foo Project
Started reading the TextFile's text from Foo's Main method. Reading file from Bin\Debug\Libs directory.
Every time I press F5 I see the latest file get copied there.
Edit "Foo.csproj" (make sure the project is closed in VS) and add this add the bottom, in place of a commented out example that is already there in every new project file (use your own paths):
<Target Name="AfterBuild">
<Copy SourceFiles="Libs\cef.pak;Libs\file2.ext" DestinationFolder="..\..\Bar Solution\Bar Project\output" SkipUnchangedFiles="True" OverwriteReadOnlyFiles="True" />
</Target>
Edit "Bar.csproj" as well, just in case changing those files doesn't trigger Foo build:
<Target Name="BeforeBuild">
<Copy SourceFiles="..\..\Foo Solution\Foo Project\Libs\cef.pak;..\..\Foo Solution\Foo Project\Libs\file2.ext" DestinationFolder="output" SkipUnchangedFiles="True" OverwriteReadOnlyFiles="True" />
</Target>

ensuring c# project dependencies are copied to output directory in Visual Studio and TFS

I am working on a project which has many dependencies which are developed on a separate team from me. We use TFS 2010. Many of my applications depend on libraries and xml files which are under active development, so I want to keep them up to date. I also don't want to create separate copies of the dll's and xml files for each application/project, but rather source them from their respective locations within the same source control repository. This should be possible using a relative path.
I tried putting the following in my .csproj file
<ItemGroup>
<Dependencies Include="..\..\Driver\Driver.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Dependencies>
</ItemGroup>
this doesn't work, either on my workstation or on the build server, however, the files show up as dependencies in the Solution Explorer, and it allows me to change the copy to output property and shows the full path the to files, which is valid.
Another thing I tried was just running xcopy as a pre-build event, which works on my local machine but does NOT copy the files to the output/TFS drop folder, so it isn't picking it up as a dependency.
Try using the Private Element instead, set to True.
<ItemGroup>
<Dependencies Include="..\..\Driver\Driver.dll">
<Private>True</Private>
</Dependencies>
</ItemGroup>
See http://msdn.microsoft.com/en-us/library/bb629388.aspx

Adding custom information to CSPROJ files

As part of our development life cycle we have a number of process that we run against the C# source in our projects.
The processes are driven off a GUI that currently reads the *.csproj file to find the source files used within the project. This works fine.
We now have a new requirement to provide some validation processes that require a call out to a web-service. The web-service needs to be provided with some credentials that are project specific. Ideally we could enter and store these credentials within the *.csproj file but I don't see a means of extending it - is there?
We don't really want to introduce a new config. file just for these settings if we can help it. Is it possible to store information like this is the *.csproj file, if not is there any other place to put it.
thanks
The .csproj file is basically an MSBuild file, as such you can extend it with custom values. If you right-click on a project in Visual Studio and choose "Unload Project", the project will "grey out" and you can then right-click again and choose Edit [ProjectFileName].csproj. You can then add something similar to the following:
<PropertyGroup Label="Custom">
<Badger>1</Badger>
</PropertyGroup>
This should be persisted when the project is modified (i.e. files added/removed) and you can retrieve the values from the file, using the method of your choice.
VS projects support "project extensions". These are custom data stored directly in csproj/vbproj files. You can very easily read and write them even from VS. For example, the following VS macro writes such custom setting:
Dim proj As Project = DirectCast(DTE.ActiveSolutionProjects(0), Project)
proj.Globals.VariableValue("MySettingName1") = "My value1"
proj.Globals.VariablePersists("MySettingName1") = True
The following reads it back:
proj.Globals.VariableValue("MySettingName1").ToString
And the code in csproj file looks like:
<ProjectExtensions>
<VisualStudio>
<UserProperties MySettingName1="My value1" />
</VisualStudio>
</ProjectExtensions>
Of course, this is persisted and will not be overwritten by VS.
I know you dismiss it but the most obvious, and probably recommended, place is in the config file. Albeit encrypted.
One config file per project does for most cases and is not a large overhead imho.

Categories