Including a file when I publish my Azure function in Visual Studio - c#

I know this seems like a simple thing but I can't find any help online.
I want to include a file (.html) along with my Azure function when I publish it using Visual Studio. Then I want to be able to access this file in my Azure function.
Why? It seems like only the .dll gets sent to the server when I publish.
This file will be an .html file that will be an email template. I want to read it in my function and then send emails out.
Any help is much appreciated.
I see I can use [send grid in Azure functions][1], but it looks like I can only send out one email and not multiple emails, which is what I want.

First, you need to add the html file to your project, and in the properties, set Copy to Output Directory to "Copy if newer".
Then in your function code, take in an additional ExecutionContext context parameter (note that this is Microsoft.Azure.WebJobs.ExecutionContext and not System.Threading.ExecutionContext). And when you need to access your html file, you can then write:
string htmlFilePath = Path.Combine(context.FunctionAppDirectory, "test.html");
That's assuming you added the file at the root of your VS project. If you instead added it in some Data folder (better practice), you'd write:
string htmlFilePath = Path.Combine(context.FunctionAppDirectory, "Data", "test.html");
See here for full working sample.

I have the same scenario as you have. However, I cannot access ExecutionContext because it is only available in requests. My scenario needs to get the template included in AzFunc project but not in the context of AzFunc's functions. I got it null when I go with the interface - implementation class approach.
Thanks to this guy, I use IOptions<ExecutionContextOptions> in my class to get the root directory of the Azure Func.
My Azure Func project (NET 6, Azure Function v4)
using Microsoft.Extensions.Options;
using Microsoft.Azure.WebJobs.Host.Bindings;
namespace AzureFuncApi
{
public class TemplateHelper : ITemplateHelper
{
private readonly IOptions<ExecutionContextOptions> _executionContext;
public TemplateHelper (IOptions<ExecutionContextOptions> executionContext)
{
_executionContext = executionContext;
}
public string GetTemplate()
{
var context = _executionContext.Value;
var rootDir = context.AppDirectory; // <-- rootDir of AzFunc
var template = Path.Combine(rootDir, "test.html"); // <-- browse for your template. Here's an example if you place test.html right in the root of your project
// return your template here, raw, or after you do whatever you want with it...
}
}
}
My different project defines the interface and uses it there, independently of the real implementation
namespace DifferentProject
{
public interface ITemplateHelper
{
string GetTemplate(); // Use this to get the template
}
}

Related

c# Local Application edit app without recompiling/reinstallation [duplicate]

I would like to store an API key in a configuration file without checking it into source control, and read the data in my UWP app.
A common solution is to store the key in .config file (such as app.config or web.config) and access it like so:
var apiKey = ConfigurationManager.AppSettings.Get("apiKey");
I'm working on a Universal Windows (UWP) app and can't access the System.Configuration namespace that holds ConfigurationManager.
How can I access AppSettings in UWP app?
Alternatively, what's the best way to access configuration data in an UWP app?
In my specific use case I needed to use an external file that is not tracked by source control. There are two ways to access data from resource or configuration files.
One is to open and parse a configuration file. Given a file sample.txt with Build Action Content (Copy to Output Directory doesn't matter), we can read it with
var uri = new System.Uri("ms-appx:///sample.txt");
var sampleFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
or
var packageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var sampleFile = await packageFolder.GetFileAsync("sample.txt");
followed by
var contents = await Windows.Storage.FileIO.ReadTextAsync(sampleFile);
Alternatively, we can use Resources. Add a new Resource item to the project, called resourcesFile.resw. To access data, use:
var resources = new Windows.ApplicationModel.Resources.ResourceLoader("resourcesFile");
var token = resources.GetString("secret");
I wrote more verbose answer in a blog post Custom resource files in UWP
It's an old question, but here my solution :
Create a partial class Config.cs (for example) with all the properties you'r needed
Add a partial method void Init()
Call Init in the constructor
Create an other file Config.partial.cs with the void Init() method filling all your properties
-> Use #if DEBUG / #else / #endif to switch from Debug/Release
-> Use exclude Config.partial.cs from Github to not import it in the repository
Now it compile and it's not in the repository
Alternatively you can set in Config.cs default (not secret) datas.
Config.cs :
public partial class Config
{
public Config()
{
Init();
}
partial void Init();
public string ApiKey{ get; private set; }= "DefaultValueAPIKEY";
}
Config.partial.cs
public partial class Config
{
partial void Init()
{
#if DEBUG
this.ApiKey = "DebugAPIKEY";
#else
this.ApiKey = "ReleaseAPIKEY";
#endif
}
}
I'm thinking that what you call "ApiKey" is the static key that an API gives you to generate an access token. If this is the case, maybe the best way to achieve this is to create a static class out of the source control with that value inside of it, something like this:
public static class MyCredentials
{
public static string MyApiKey = "apiKey";
}
Then you access that value easily from your code:
var myApiKey = MyCredentials.MyApiKey;
If you want to store values in a plain-text file instead you will have to write/read it manually using StorageFile and FileIO classes.
Instead, if "ApiKey" means the dynamic access token, then the best solution is use ApplicationDataContainer as stratever says.
You don't need to create a configuration file. UWP has a built-in solution to store local settings/configurations. Please check this tutorial:
https://msdn.microsoft.com/en-us/library/windows/apps/mt299098.aspx
Using ApplicationDataContainer, you will be able to get a value by key:
Object value = localSettings.Values["exampleSetting"];

Get value of version out of project.json

In a DNX application, which uses a "project.json" file, is there a way to read the value of the "version" property out of the "project.json" file?
I'm writing a library that writes something to the current HTTP response and I would like to show the version of the application in there.
Any help on how this can be done is highly appreciated.
If you set the version attribute during build (or in any other way) you can do this like that:
using System;
using System.Reflection;
[assembly:AssemblyVersionAttribute("1.2.3")]
namespace Test
{
class Program
{
public static void Main()
{
var assembly = typeof(Program).GetTypeInfo().Assembly;
var name = assembly.GetName();
Console.WriteLine($"{name.Name}: {name.Version}");
}
}
}
I did it using the new dotnet cli which is replacing dnx but it should work with dnx dnxcore50 as well.
Are you writing a Class Library or an ASP.NET application?
If a class Library, you could copy the version string to a resource file that you read in during run-time to grab the version. It's kind hard to do this sort of thing with class libraries since you don't get the beauty of a Startup and IoC.
If ASP.NET, then just add a version into your appsettings.json configuration (or a custom json file to store settings) and read it in at startup: http://docs.asp.net/en/latest/fundamentals/configuration.html
Multipe ways of doing this if you are running in a the web application, not a class library.
First way custom attributes data (should check if attribute is available):
this.GetType().Assembly.GetCustomAttributesData()
.First(x => x.AttributeType.FullName == "System.Reflection.AssemblyInformationalVersionAttribute")
.ConstructorArguments[0];
Second way
var name = this.GetType().AssemblyQualifiedName;
name = name.Substring(name.IndexOf("Version=") + 8);
var verion = name.Substring(0, name.IndexOf(", "));

ConfigurationManager and AppSettings in universal (UWP) app

I would like to store an API key in a configuration file without checking it into source control, and read the data in my UWP app.
A common solution is to store the key in .config file (such as app.config or web.config) and access it like so:
var apiKey = ConfigurationManager.AppSettings.Get("apiKey");
I'm working on a Universal Windows (UWP) app and can't access the System.Configuration namespace that holds ConfigurationManager.
How can I access AppSettings in UWP app?
Alternatively, what's the best way to access configuration data in an UWP app?
In my specific use case I needed to use an external file that is not tracked by source control. There are two ways to access data from resource or configuration files.
One is to open and parse a configuration file. Given a file sample.txt with Build Action Content (Copy to Output Directory doesn't matter), we can read it with
var uri = new System.Uri("ms-appx:///sample.txt");
var sampleFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
or
var packageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var sampleFile = await packageFolder.GetFileAsync("sample.txt");
followed by
var contents = await Windows.Storage.FileIO.ReadTextAsync(sampleFile);
Alternatively, we can use Resources. Add a new Resource item to the project, called resourcesFile.resw. To access data, use:
var resources = new Windows.ApplicationModel.Resources.ResourceLoader("resourcesFile");
var token = resources.GetString("secret");
I wrote more verbose answer in a blog post Custom resource files in UWP
It's an old question, but here my solution :
Create a partial class Config.cs (for example) with all the properties you'r needed
Add a partial method void Init()
Call Init in the constructor
Create an other file Config.partial.cs with the void Init() method filling all your properties
-> Use #if DEBUG / #else / #endif to switch from Debug/Release
-> Use exclude Config.partial.cs from Github to not import it in the repository
Now it compile and it's not in the repository
Alternatively you can set in Config.cs default (not secret) datas.
Config.cs :
public partial class Config
{
public Config()
{
Init();
}
partial void Init();
public string ApiKey{ get; private set; }= "DefaultValueAPIKEY";
}
Config.partial.cs
public partial class Config
{
partial void Init()
{
#if DEBUG
this.ApiKey = "DebugAPIKEY";
#else
this.ApiKey = "ReleaseAPIKEY";
#endif
}
}
I'm thinking that what you call "ApiKey" is the static key that an API gives you to generate an access token. If this is the case, maybe the best way to achieve this is to create a static class out of the source control with that value inside of it, something like this:
public static class MyCredentials
{
public static string MyApiKey = "apiKey";
}
Then you access that value easily from your code:
var myApiKey = MyCredentials.MyApiKey;
If you want to store values in a plain-text file instead you will have to write/read it manually using StorageFile and FileIO classes.
Instead, if "ApiKey" means the dynamic access token, then the best solution is use ApplicationDataContainer as stratever says.
You don't need to create a configuration file. UWP has a built-in solution to store local settings/configurations. Please check this tutorial:
https://msdn.microsoft.com/en-us/library/windows/apps/mt299098.aspx
Using ApplicationDataContainer, you will be able to get a value by key:
Object value = localSettings.Values["exampleSetting"];

Get the path from a SpecFlow feature file in a Step Definition

Is it possible to retrieve the path of a SpecFlow feature file during runtime in a Step Definition?
Snippet:
[Given(#"Some given statement")]
public void GivenSomeGivenStatement() {
var featureFilePath = // retrieve the path of the feature file
// that executes this step.
}
Context:
We do testing on databases and queries. The source data is created in Excel files and .SQL files (for check queries). These source data are large datasets, not feasible to put into the feature files itself or use the SpecFlow.Plus.Excel extension.
To keep the data close to the feature file, we want to have this data in the same folder as the feature file itself. To achieve this, we need the path to this feature file, so we also have the path to the testdata.
Here's a suggestion. This is just something I put together quickly so lots of room to improve. It relies on the Feature file name being identical to the title of the feature you provide in the description. It also assumes you have a conventional folder structure for your SpecFlow VS project as there is a lot of string manipulation.
Firstly, the calling code should use the SpecFlow BeforeScenario attribute. Something like this:
public void BeforeScenario()
{
//grabs Feature Title from SpecFlow context
var featureName = FeatureContext.Current.FeatureInfo.Title;
//Calls method to obtain path of file
var featureFilePath = GetFeatureFilePath(featureName);
}
The method GetFeatureFilePath will then look like this:
private static string GetFeatureFilePath(string featureName)
{
string startupPath = Environment.CurrentDirectory;
var splitStartupPath = startupPath.Split(new[] {"\\"}, StringSplitOptions.None);
var featureFolder = splitStartupPath[0] + #"\\" +
splitStartupPath[1] + #"\\" +
splitStartupPath[2] + #"\\" +
splitStartupPath[3] + #"\\" +
splitStartupPath[4] + #"\\" +
splitStartupPath[5] + #"\\Features\";
var dir = new DirectoryInfo(featureFolder);
foreach (var fi in dir.GetFiles())
{
if (fi.FullName.Contains(featureName))
return fi.FullName;
}
return "No Feature File Found With Title: " + featureName;
}
It grabs your current directory and splits it to the point where the Features folder should be. It then iterates through each feature file until it finds one that contains your feature title in its path name and returns that as a full path.
I'm not aware of any other way to get this currently.
I don't think knowing the path to the feature file will be possible, as the feature file is used to generate a file containing the unit tests and this is compiled and copied to the test run directory.
The simplest thing will be to set the files as part of the solution and then have them copied to the output directory when the project builds.
If you are using NUnit as the test framework then the files should be in the same directory as the tests are executing so you should just be able to load them without specifying any path, or using the Assembly.GetExecutingAssembly().Location to findout where the code is actually executing.
If you are using MSTest then you need to add a [DeploymentItem(FileToDeploy)] attribute to the test to ensure that the file actually gets deployed with the tests when they are run. Unfortunately as Specflow generates the tests it won't add this for you. To solve this you need to create a partial class which has the same name as the class which contains the tests. This class is called the same as the feature with 'Feature' tagged on the end. So if you have this in your feature:
Feature: Do A Thing
The your test class will be called DoAThingFeature
so you need to create a partial class like this:
[DeploymentItem("FileToDeploy.ext")]
public partial class DoAThingFeature
{}
to ensure that MsTest copies the file you need to the correct directory.
Edit
based on your comment you could maybe do something similar to this
add tags to your feature #hasFiles #source:myFile.xlsx
Then you could add this class:
[Binding]
public class DeployFiles
{
[BeforeScenario("hasFiles")]
public void CopyFiles()
{
..in here find the current executing directory and search
..the subtree for any files defined in the
..ScenarioInfo.Tags array that start with `source:` and copy
..them to the current executing directory
}
}
then any scenario tagged with the #hasFiles will deploy any files specified by #source tags to the root directory where the tests are running.
Not pretty and I'm not certain it'll work, but it might.
maybe this could help you , in .net 4.5 you can get the hold of the path to the caller, take a look at this thread source path in .net 4.5

Visual Studio - Unit tests loading resources in the project

The goal is to run some tests given some data in those Xml files.
How would you easily load a given Xml file into an XmlDoc within the unit test methods?
Current state is:
XmlDocument doc = new XmlDocument();
string xmlFile = "4.xml";
string dir = System.IO.Directory.GetCurrentDirectory() + #"\Msgs\"
//dir is then the value of the current exe's path, which is
//d:\sourcecode\myproject\TestResults\myComputer 2009-10-08 16_07_45\Out
//we actually need:
//d:\sourcecode\myproject\Msgs\
doc.Load( dir + fileName); //should really use System.IO.Path.Combine()!
Is it just a simple matter of putting that path in an app.config? I was hoping to avoid that, given the possibility of different paths on developer machines.
Question: How would you write the algorithm to load a given Xml file into an XmlDocument in the unit test method?
There is a Visual Studio Unit Testing feature for this: DeploymentItemAttribute
I use this feature to copy all xml files in a given project folder to the unit test output folder, before testing if all required files are present.
You can use this attribute with your unit tests to copy specific files from the Project folder (or anywhere else) to the Unit Test output folder. Like so:
[TestMethod()]
[DeploymentItem("MyProjectFolder\\SomeDataFolder\\somefile.txt", "SomeOutputSubdirectory")]
public void FindResourcefile_Test()
{
string fileName = "SomeOutputSubdirectory\\somefile.txt";
Assert.IsTrue(System.IO.File.Exists(fileName));
}
You can also copy the contents of whole folders:
[TestMethod()]
[DeploymentItem("MyProjectFolder\\SomeDataFolder\\", "SomeOutputSubdirectory")]
public void FindResourcefile_Test()
{
string fileName = "SomeOutputSubdirectory\\someOtherFile.txt";
Assert.IsTrue(System.IO.File.Exists(fileName));
}
The first parameter is the source, the second the destination folder. The source is relative to your solution folder (so you can access the Unit Test project of the project being tested) and the destination is relative to the output folder of the unit test assembly.
UPDATE:
You need to enable Deployment in the Test Settings for this to work. This MSDN page explains how (it's real easy): http://msdn.microsoft.com/en-us/library/ms182475(v=vs.90).aspx#EnableDisableDeploy
You can build those files into your executable (set their "Build Action" property to "Embedded Resource") and then get them using the Assembly.GetManifestResourceStream method.
In the unit test project add a post-build event that copies the XML file to the output directory. Then, you can use your original code to get the XML file.
The post build event will look like something like this:
copy $(SolutionDir)file.xml $(ProjectDir)$(OutDir)file.xml
You may also need this to add to your path:
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
I use a helper class to deal with getting basic paths I might want to access in my Unit Tests.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Brass9.Testing
{
public static class TestHelper
{
public static string GetBinPath()
{
return System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
}
public static string GetProjectPath()
{
string appRoot = GetBinPath();
var dir = new DirectoryInfo(appRoot).Parent.Parent.Parent;
var name = dir.Name;
return dir.FullName + #"\" + name + #"\";
}
public static string GetTestProjectPath()
{
string appRoot = GetBinPath();
var dir = new DirectoryInfo(appRoot).Parent.Parent;
return dir.FullName + #"\";
}
public static string GetMainProjectPath()
{
string testProjectPath = GetTestProjectPath();
// Just hope it ends in the standard .Tests, lop it off, done.
string path = testProjectPath.Substring(0, testProjectPath.Length - 7) + #"\";
return path;
}
}
}
Sometimes my interactions with paths are more complex; I often use a central class I name "App" to indicate some basic details about the application, like its root folder, its root namespace and module, etc. Classes will sometimes depend on App's existence, and so instead I'll place an init method on App that uses code like the above to initialize itself for test harnesses, and call that method from the Init command in a Unit Test.
(Updated)
Old Answer
I found this helps for getting arbitrary paths to access files in the project folder you intend to test (as opposed to files in the Test project folder, which can make busywork if you need to copy things over).
DirectoryInfo projectDir = new DirectoryInfo(#"..\..\..\ProjectName");
string projectDirPath = projectDir.FullName;
You can then use either of those variables to access whatever you need from the related project. Obviously swap "ProjectName" out for the actual name of your project.
Resources are just resources and that's it, no need to complicate. If you don't want to embed them then you could add these files as "Content" resources to your project and set them to Copy always. Then specify the sub-folder in your code:
var xmlDoc = XElement.Load("ProjectSubFolder\\Resource.xml");
This will automatically load the resources from the project output (running assembly location) bin\$(Configuration)\ResourceSubfolder\
This works for all types of projects, not just unit tests.
I would just put the path in the app.config and load from the default path. In my team, i am really anal about developers changing paths, so i make all my developers have the same exact paths and files on their computers, so i dont have an issue of any rogue developer changing a path to suite his workspace.
For example , all developers in my team must use C:\Project\Product\Module, etc etc. I also make sure all their software installed also is standard. This way, i can ghost any machine into any other easily.
I think in VS.NET 2012 DeploymentItem attribute works without any Test Settings configuration.

Categories

Resources