Now I have seen this question before on SO in a variant ways, but surprisingly not in this form:
I have a solution with multiple web services (projects) that need to talk to each other. After publishing each of these web services might end up on a different machine with a different database. To tell each web service where all other web services are, I want to maintain a single config file during development.
I would like to expect that after publishing the config to be present in each published project. And I would like to expect the config file to be editable after publishing, so I can swiftly migrate a certain web service and then just edit all config files of the other web services.
I don't want to do this in the database, for the config file its self should also hold connection settings to the database(s).
I came across the following ideas/thoughts/questions:
I have a dll project called 'common' that is referenced by other projects. Let's give that one a shared.config and build a class in that project that can be used to read out the shared.config by doing System.Configuration.ConfigurationManager.OpenExeConfiguration("shared.config"). Just need to make sure the shared.config will be published along with the DLL.
I would favor this solution, as it would also let me keep a web.config inside each project having just the project specific settings. And have the shared.config having the shared settings. But I read on SO that this should not be considered lightly and could have some unwanted side-effects, like file-access-issues; though I wonder if this would apply to my case. Also I would like to ask your help here on how to actually realize this as I don't think Visual Studio supports app.config for DLL projects out of the box.
I also thought about creating a shared.config file in the Solution Items. Then linking that file inside each project. And in the Web.config of each projects, add: <appSettings configSource="shared.config" /> pointing to the linked file in that project.
Though I cannot find any reason why not to do this, first implementation failed. It seems (at least during development), c# cannot find the linked shared.config file. I'm guessing linking files is not done instantly nor maintained after creating the linked file, but the file is only copied to the projects WHEN I do a publish. Thus leaving the file missing during development. Is this correct?
The config files are app specific. This mean that you can add a config file to a class library but the file will then by used by the app (windows service, webservice and so on) referencing the library.
Same thing for external configSource, this are app specific as well and need to be included withing the project using it.
So if your solution is composed by 2 projects you then need 2 config files. One for each project.
While for a windows based application(services, winforms) the expected folder for config files is the bin directory, for web based projects this will be the directory is the root folder of the virtual directory.
This said, using a shared config file looks the easier solution (and you don't have to copy the app.config from the class library for each project). Here are the steps :
Create a solution folder.
Add the config file to it.
Add the file as a reference for each project needing it. Right click the project and Add existing item - > Choose the file and Add as link
Ensure the file is always copied by setting the copy option (properties of the file) with Copy Always.
At this point you should have the config file deployed into your project directory everytime you compile the solution.
EDIT:
I'd avoid looking into the bin for config files within a web app, the
convention is that file should be in the root, so I would avoid the
first option.
Linked files end up in the bin after building the project. Try the same steps for importing the file but this time simply add it (not as link) and it will be deployed as content in the root of your site, so it can be always available.
If your hosting in IIS it is possible to have a single web.config file at the root site level but Giorgio is right in that app.config files are app specific. it is possible to use custom build steps to automate the copying of config files across multiple projects so personally I would go with that.
This actually drove me a bit crazy. In the end I fixed it like this:
Created a Shared.config file in the dll project 'common', having the contents look like any ordinary web.config/app.config.
Set the file to be Content and Copy Always, so it would surely be copied out to all projects that reference project common. (Though the config file will indeed end up in the bin folder.
Created the class SharedConfiguration inside the common project. The really tricky part was having to use OpenMappedExeConfiguration() , and getting the path to the executable directory (including bin, and without file:// in front of it).
Now when I want to access a setting from the shared settings, I do SharedConfiguration.instance.AppSettings.Settings["CubilisEntryPointUrl"].Value.
(I cannot use SharedConfiguration.instance.AppSettings["CubilisEntryPointUrl"] directly because of this issue)
.
public static class SharedConfiguration
{
public static readonly Configuration instance = GetConfiguration("Shared.config");
private static Configuration GetConfiguration(string configFileName)
{
ExeConfigurationFileMap exeConfigurationFileMap = new ExeConfigurationFileMap();
Uri uri = new Uri(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase));
exeConfigurationFileMap.ExeConfigFilename = Path.Combine(uri.LocalPath, configFileName);
return ConfigurationManager.OpenMappedExeConfiguration(exeConfigurationFileMap, ConfigurationUserLevel.None);
}
}
Related
I am new in mvc and c# and I can't solve following problem:
I am trying to create a folder named "Items" in solution folder.
I have tryed to use CreateDirectory method:
Directory.CreateDirectory("~/Images");
But it didn't work for me - folder wasn't created ..
Partly working solution was to create a folder by :
Directory.CreateDirectory(Server.MapPath("~/Images"));
"Items" folder was created, but it is not included in the solution:
How to create folder in solution directory so that it is included in project ?
(I needs to by done by code not by hand)
You need to understand what solution and csproj file is used for
In general, they're being designed and used for development with Visual Studio, and once the project is compiled, all these files will be ignored and excluded from the deployment package
Directory.CreateDirectory(Server.MapPath("~/Images"));
The code above simply create the directory if not existed yet in the deployment package at run-time, so you won't see it in your solution unless you run the project locally (either debug/release mode, it does not matter here). However, everything will run normally in hosted environment (ex: IIS).
For your information, here's the brief of what solution and csproj is
solution (.sln) file: contains information to manage one or many individual projects, contains build environments (for each project), start up mode (useful when you want to start multiple projects in one run), project dependencies and so on. Take a note that VS also read from suo file (solution user options) which is used to defined user-custom preferences (you should not include the .suo file in the version control, because it's custom settings)
csproj file: define the structures of project, what the namespace is, what is static folders, embedded resources, references, packages, etc.
Lastly, if you create the folder manually, VS will auto include that folder into deployment package AND csproj, but depends on the file type, you might need to change the Build Action and Copy To Output Directory in file properties.
Hope it helps.
A deployed web application on a web server doesn't have any notion of Visual Studio solution or projects. So the Directory.CreateDirectory(Server.MapPath("~/Images")) is the correct way to create a folder inside your web application at runtime but we cannot be talking about including it into a solution because this hardly makes sense in a pre-compiled web application. If you create the directory on your local development machine, you could always manually include the folder to the corresponding .csproj file, but at runtime this will not make any difference whatsoever.
The reason I wanted to create a folder (if didn't exist) was to make sure it exits before I try to store image in it.
After reading posts here and a few google searches I have concluded that the proper way to handle image upload would be
To create (In my case) folder "Images" by hand to be sure it exists
Then storing uploaded img in existing folder:
string path =Server.MapPath("~/Images/"+ UploadedImageName);
file.SaveAs(path);
In an Visual Studio environment, Project A (ASP.NET) references Project B (C#) in my solution like this:
Solution
├─Project B
│ ├─data.txt
│ └─process.cs (a class BB with static initialization new FileStream("data.txt"))
└ Project A (referencces Project B)
├─bin
│ └─data.txt (copied from project B each time project B changes)
└─Controllers
└─mycontroller.cs (references the class BB)
The problem is that when I run the application, the working directory is C:\Program Files (x86)\IIS Express\, so that data.txt cannot be read from the compiled version of process.cs which is in bin.
For the moment, to solve the problem, I manually copied data.txt to this folder, but this solution is not viable.
Note that changes to B must be coherent with other projects depending on B, which are not all ASP.NET project.
What changes should I make so that data.txt is accessible from my project without relying on me to copy the data.txt file to the IIS Express directory?
I would like to port my program to Azure Online and I cannot rely on this method. Thank you for your help.
Other linked answers:
This answer is ASP.NET - specific, I cannot add server.MapPath because the project does not know about it.
This answer references project paths, but does not give me an hint about how to modify them.
"Note that changes to B must be coherent with other projects depending on B, which are not all ASP.NET project"
Not sure what coherent would mean to you in context of other projects which depend on project B...
But following options come to mind -
Embed data.txt as a resource in the assembly generated for project B. Project B, can then read the file as a resource (This assumes, file contents do not need to be modified after the build)
See ResourceManager class for handling resources embedded in assemblies.
http://msdn.microsoft.com/en-us/library/system.resources.resourcemanager(v=vs.110).aspx
If it works for all clients of Project B, scan sub-directories for the file.. This is more hackish.. but really depends on the scenarios for project B.
Ensure that data.txt is being deployed somewhere. Then, make your library take the path to it or the base directory path as an argument. The caller of the library is the application which has concrete knowledge of how to obtain the file's path.
Or, embed the .txt into the DLL as a manged resource.
To me your problem is not about copying the file - but its location. A shared file should be kept in a shared / central location accessible by all applications. In your current situation this could be (and this isn't exhaustive)...
Database Blob
Explicit File Location
Online, retrieved over HTTP
Online, retrieved over FTP
Networked location
Running a small TCPIP server between the programs so that one acts as the source and child processes request the file.
In respect to porting your application to Azure, Azure provides a BlobStorage along with functionality to access the file in an unsecured and secured manner (see Shared Access Signatures).
HTH
Can't you just configure your project B with your project A ? I mean giving the path of your txt file to some static field of a configuration class from project A to project B.
I have a Visual Studio 2010 Solution that contains three projects:
A Windows Service which will read Data from a SQLite Database to perform actions
A Winforms App which will provide a method of configuring the behaviour of the Service (by updating the SQLite Database)
A Class Library Project to abstract all database access away from the service and the config app (making it easier in the future to update anything having to do with the database without having to hunt down queries in the other two projects)
All of these projects are in the same solution, and I have added references from the Winforms App and the Service to the class library. In both projects I am able to see the classes from the class library and interact with them, but I am having an issue. I have created the database in the /Resources/ directory of my class library project (because to me the "common" project is the only sensible place to store the common database), however whenever I attempt to access the database in the Winforms app, it is not returning data that I know is in there. Since System.Data.SQLite has the default behaviour of creating an empty database file if the file isn't found (an odd choice in my opinion), I can't even go back and tell if the database exists or not.
This leads me to suspect that I am not understanding properly how files from one project are referenced in another. Here is what my project looks like:
WorkModeCommon Contains the classes SQLiteDatabase and ScheduleManager, where ScheduleManager has a SQLiteDatabase() and SQLiteDatabase interacts with Resources/WorkModeSchedules.s3db
Both the WorkModeConfigApp and the WorkModeService have a WorkModeCommon.ScheduleManager(), which should in theory take care of all of the database interaction.
Do I have a major flaw in my design, or could someone point me to a resource which could help me solve the problem I'm having?
I think this is what's happening.
When you reference the common class library, it's simply using the .dll output as the reference, since it's the only output.
However, if you right-click on the .s3db file and go to its Properties, you can set its Copy to Output Directory setting to Copy if newer, that way the database file itself is in the output directory, so the .dll file can see it.
Now, when your form or service access the .dll file from the output directory of your common class library project, it'll reference the .s3db file, too, so then they'll all see the same data.
Whether this is a good design or not depends on your needs.
If the form and the service are both looking at the same data at the same time, then you have to make sure they're at least looking at the same file, not at their own copies of the .s3db file.
If it's just the form or the service accessing the database, I'd be ok with it, but since multiple processes (the form and the service) are accessing it, a common database server is a good choice.
Compiled classes are visible to outside assemblies that reference them as long as their visibility is Public (with some exceptions). Non-compiled files are a different story. You can specify the build action as "embedded resource", which will allow you to access the file from referencing assemblies, albeit in a read-only fashion. The other option, and likely what you want, is to specify "copy to output directory" as either "copy always" or "copy if newer." This will copy the file to the output directory at build time.
When you start debugging your WorkModeConfigApp, the app runs from its bin\debug directory and has no way to reach the resource directory of the class library. Simply referencing the class library doesn't means that VS copy the resource directory of the class library inside the bin/debug of the Config app. If you set the Copy Local = true for the class library VS will copy the compiled DLL inside the bin\debug of WorkModeConfigApp but doesnt' copy the content of the resource directory
On the other way, you could set the property copy to the output directory for the .s3db file, in this way the file and its directory will be copied in the bin\debug of the WorkModeConfigApp. But this will be the source of other problems because during debug your test database risk to be overwritten from the one coming from the class library.
I think that your best option is to save inside the configuration files of the service and of the config app where to locate this file and don't mess with the aforementioned property.
We are talking about a Database so probably in the config file for App and service you need to add a connection string. You could add the required nodes to your App.config, see the example below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
</configSections>
<connectionStrings>
<add name="WindowsFormsApplication1.Properties.Settings.MyDatabaseConnection"
connectionString="Data Source=C:\ProgramData\MyAppName\/WorkModeSchedules.s3db;Version=3;Pooling=True;Max Pool Size=100;"/>
</connectionStrings>
</configuration>
You could then access this value using one these methods:
string cnnString1 = ConfigurationManager.ConnectionStrings["MyDatabaseConnection"];
string cnnString2 = Properties.Settings.Default.MyDatabaseConnection;
(The ConfigurationManager method requires the reference to System.Configuration assembly)
Ok folks, I've solved my problem. What I did is include a copy of the DB file in each project, and set the "Copy To Output Directory" property on all but one of those instances (the "Common" project) to "Do Not Copy". After that I changed the output directory for all three projects to the same directory (more specifically, I created centralized Debug and Release directories and pointed the proper build configurations to the proper directories). I am now able to test successfully using a single DB file and a centralized class library!
I'm trying to use application settings with a C#.NET project I am working on. But I can't seem to get it to return anything other then the default values. Through the project properties I've added a single setting, DBConnectionString, and set its value to a connection string I want to use. Its scope is set to "application".
Doing this created a number of files including Settings.settings, Settings.Designer.CS, and app.conifg. From what I understand the two Settings.* files define a custom Settings class that derives from ApplicationSettingsBase. The Settings class then has custom, type safe, properties that can be used to set and retrieve each setting. The app.config file is a XML file that stores the actual settings values.
When I build my project it looks like the app.config file is copied to the target directory as MyApplication.dll.config. My program runs fine and is able to use the default connection string.
Next I tried to edit the MyApplicaiton.dll.config file to change the connection string. I ran my program again, but it continued to use the default value. I noticed that in my Settings.Designer file there is a DefaultSettingValueAttribute with the original default string. I tried removing this attribute, but then when I tried to retrieve the connection string setting it just returned null.
This is the code I'm using to read the connection string.
string conn = Properties.Settings.Default.DbConnectionString
What am I doing wrong? How can I get it to return the value in the settings file and not the default value?
Update:
Sorry I should have mentioned this. I'm actually writing a plug-in for another application through a public API. So my project is a DLL not an EXE.
You cannot read settings from *.dll.config files. If you library needs any special settings you need to put them in your app.config or web.config files.
EDIT: You can include the external config files in the main application or web config file. Look here for details.
This question discusses how to manage configuration files for large projects.
Settings files and .config files are different things (I do not know why VS automatically added a .config when you created a Settings file). But, the settings file is compiled into a class and is referenced like you said. If you decompile the dll with .NET reflector the Settings class will be in there. It is used for holding constant values or external resources. For example: error message strings, icons, or images.
The config file is for settings which can change frequently or between environments (dev, test, prod). For a connection string you should use the <connectionStrings> section of the config file. And the property can be referenced using System.Configuration.ConfigurationManager[ "connectionStringName" ].
However, from your original post it looks like your .dll is going to be used in a larger project (either an .exe of web project). One thing to note is that all projects only use one .config file. And that is the config file for the main project. Websites the web.config file, and exe's use XXX.XXX.XXX.exe.config (as you saw, *.exe.config files are renamed copies of the app.config files). dll's do not have usable config files. All dll's will look at the main project's .config file to retrieve information.
If your connection string is never going to change then by all means use the Settings file. Otherwise, use a config file and let the developer of the main project determine what to populate the connection string with.
I have a config file in my C# class library called MyLibrary.config, in vs 2008.
I created another project, say a simple console app, add reference by "Browsing" the MyLibrary.dll in the bin directory of the class library project, and when I compile, the MyLibrary.config is not including in the bin directory of the output in the console app.
How can I set it so I can include it when I reference the dll?
Cheers
You can't. Your console application is expecting to find a config file with prefix the same as the name as the console application (MyConsoleApplication.exe -> MyConsoleApplication.exe.config.).
In some situations you can share a config file by using the file attribute on the appSettings element:
<appSettings
file="path">
</appSettings>
Note that path is relative to the executing assembly.
As a side note, DLLs do not even use the config file that you've defined in the project. Again, configuration information is read from the a config file with prefix the same as the executing assembly. Thus, even when MyLibrary.dll tries to yank configuration information out of a config file, it will be reading the config file for the executing assembly, not MyLibrary.dll.config.
For more on how config files work, see MSDN.
The standard way to use a config file is to have it the same as the executable, adding a reference to a dll will not include its config file and as far as I know dll's don't load config files on their own, rather they rely on the executable that reference them.
Beyond not being able to do this, I would also advise against this approach.
Rather than trying to tighly couple your settings to the DLL library, consider more of a "Dependency Injection" type approach - i.e. where you pass in the value dependencies (i.e. settings) to the code you are calling (i.e. the library).
The advantage in this is you are not tied to a single method of storing settings. You can then use a database, different config file formats... even hard-coding. It also makes unit testing easier by removing the external file dependency.
There are different ways to implement this, however one example is to pass the configuration settings into the constructor of the class(s) that uses them.