I need develop some application, that will be distributed to user as a single executable file. User should click to some button like "Download" and get exe file, then he executed it, and upload results back to my site. App should not contain any installer or something like this, just run once and get result.
My application have a main executable like "myapp.exe" and several data files, that depends on current user. Now i have to generate SFX zip archive, that contains myapp.exe, datafiles and current user config. When user click "download", i'm adding user data to archive and provide it to user.
Problem is that SFX archive is very boring and difficult to maintain thing. I can't change it's interface, i can use only one or two zip libraries, that can create SFX arxhives.
Is there any way to use another container or pack user data into resources of my utility "on the fly"?
I've been doing that for an application where i needed to identify which user it was without asking for any credentials. Basically, some kind of token was bundled within application before download and then sent to the server.
From what i've found, there are 2 methods :
Using WiX: build the XML, call candle + light, send to client
Making a single MSI and editing its database just before sending it to client
We chose MSI database editing for its simplicity of implementation, but i've seen WiX in production recently and the result is pretty neat.
You can use Mono Cecil to programmatically alter assemblies, including their resources. In your case, you could use it to modify your assembly pre-download to add/modify embedded resources that contain the data for the specific user.
byte[] userData = ...;
EmbeddedResource resource = new EmbeddedResource("UserData", ManifestResourceAttributes.Public, userData);
assembly.MainModule.Resources.Add(resource);
You can then read the added/modified resource(s) (at runtime, post-download) using Assembly.GetManifestResourceNames and Assembly.GetManifestResourceStream.
Related
My question is essentially the same as this one but for a Windows Store App, c# and Visual Studio. I want to have an easy way to keep secret values in the project, in a file that can be ignored in (not checked in to) source control. How should I structure my project to store the app secret in a way that makes building/source control easy?
My first idea was to store it in an XML file (not checked in), and load it at runtime, but this leaves it available to the user who installs it, so it should be done at build time. How can I store a couple secret values and have visual studio replace them in my code when my project is built?
In my company we decide to you following solution. In config file we link sections with "secret" values in external configs.
External configs are on source control. First it wasn't but after a problem when our build server lost a disk we decide it it safer to store it on a place which has backup. The folder in source control (can be also on file server) is really restricted to read and write to only people who needs this. Build process checkouts "project" folder plus "configuration" folder and do build. After build "configuration" folder is deleted. Access to build server is also restricted.
One option is to store the secrets in source control, but store them in an encrypted form. In your development or build environments, use a environment variable to store the key, and decrypt on the fly. That way you get the benefits of source control while keeping your info safe.
It is possible to do this even if you are using app.config or web.config, you just need to modify the configuration from code at startup.
Erick
Updated
If you put a secret in an untrusted area (e.g. public source control), it is vulnerable. Even if it's encrypted, with enough diligence it can be retrieved.
The only way to really keep it out of reach is to have an external service that interacts with the 3rd party API. That has its own trade-offs (e.g. user authentication as you mentioned in comments). Especially if your developers need to utilize the 3rd party API when testing, I see no other alternative that will limit the secret's exposure.
Create a new class file in your project that has slots for all of your secret values, and holds dummy/test values for all of them. Check that into source control with the rest of your project, so that anybody building it without access to the secrets will get some sort of test version.
Then, create a copy of that class file with the real secret values, and put it somewhere outside of source control. Write a batch script in the pre-build event that looks for this class file, and if found, replaces the dummy file that is included in the project with it.
This way, your project can still be in source control and anybody can check it out, build it, and run it in the test mode. Your secret file/values are stored on your build server only, so only when you build the project there will it have the real values.
Do remember to back up your secrets file somewhere. And also remember that .NET code can be decompiled easily, so your secrets may not be as secret as you hope them to be - any user with a .NET reflector can see all of the code in your release assembly, including your secret class.
I have a file called middle.config that is deployed in the same directory as an exe, but I need to update values in this file. That means that I have to go to C:\Program Files (x86)\ directory to access the file. Although it is named as a .config file it does not follow the usual schema of a .config file. It looks like this:
<configuationSettings>
<middleSettings
groupName="XYZ"
forkName="SomeDbName"
dbServerName="123.123.123.123"
cnnTimeoutSeconds="30"
cmdDefaultTimeoutSeconds="30"
cmdMediumTimeoutSeconds="60"
cmdLongTimeoutSeconds="480"
/>
<userKeys>
<Assemblies value="C:\assemblies\" />
</userKeys>
<friendlyDbName value="NiceData"/>
</configuationSettings>
I'm able to read and manipulate the content with Xml, but when I try to save the file back, a "No Permissions" error is thrown. I cannot relocate the file. I'm stuck with this legacy schema so I'm not able to treat it like a normal .config file using ConfigurationManager.OpenExeConfiguration. I cannot define sections or groups on this schema (I've not been able to anyway). All my users are Administrators on their local machines.
How do I overwrite or delete and replace this file while it is in a protected directory(my assumption about the permissions error)? Failing that, is there a way to access this schema somehow with ConfigurationManager.OpenExeConfiguration.
{edit starts here}
There are three applications in this scenario, A, B, and mine C. Application A does not know about any other applications. It can connect to many, many databases, and it drops a single file 'middle.config' that contains pointer info to the last database location that was used by the last Application A session. Application B, let's call it an import/export application, only operates on the last Application A database location. Application B reads the 'middle.config' file for database pointer info and then executes console commands against that database. It performs bulk dumps or bulk imports for selected portions of the database.
This was the situation when I come along to build application C that uses the import/export application B to fetch, blocks of data and return them to the database. So, in order for application C to use Application B
against any database, application C must modify the 'middle.config' file so that application B will find the correct database. Application C is new and the other two are legacy. I either find a way to make this work, or I force the user to start Application A and point to the database of interest, then close Application A. This is VERY unhandy.
{edit ends here}
It is not advisable to write data files to the program files directory, as this requires elevated permissions. Giving a program elevated permissions just to update a config file clashes with the Principal of Least Privilege, which states that
a particular abstraction layer of a computing environment, every
module (such as a process, a user or a program depending on the
subject) must be able to access only the information and resources
that are necessary for its legitimate purpose
It's not a "legitimate purpose" to give the process elevated permissions (that can allow it to do many harmful things) just to update a config file. MS recommended practice is to write that type of data elsewhere.
Instead, consider storing the config file in a subfolder of the ApplicationData folder.
Suggested that your app is creating its own location under the AppData location folder for the current user instead of writing to files under location where the the app is installed (especially if under Program Files which is very strict.) Not suggested to force the user to run as Administrator for your application either.
Your assumption about protected directories is correct. Program Files has an Access Control List which prevents modification by processes running as standard users and, on Vista upwards, even by administrator processes which are not running elevated. Accessing the file using the standard configuration classes would not get around this.
If you absolutely can't move the file (Eric J. is right when says that writing to Program Files after installation is a bad idea), then you could embed a manifest in your config file-editing program which will try to force elevation with a UAC prompt at launch. Of course, the best solution would involve a) using standard config schema and b) keeping user data in user-writeable locations, but sometimes that isn't possible for legacy reasons.
I'm not aware of any way to persuade ConfigurationManager to read a non-standard schema, unfortunately.
Move the logic to a separate process and launch it with admin privileges from your current application.
From a different angle, look at this: Writing custom sections into app.config
I found the linked article to be very useful. Not sure it is going to answer all your questions though.
I have a C# winform application that accesses data from an MS Access database. This means my applications requires at least 2 files, the .exe file and the .accdb file. Is it possible to include the database in the .exe file, so my solution consists of a single file (the same way you would include an image in the project resources)? If it is possible, are they any major reasons why it shouldn't be done and how would you access the data from code? The project is a only a little one for personal use so if performance is hit it doesn't matter too much.
thanks in advance
It can be done. Simply add it to your project as you would add any other file (right click project -> Add -> Existing Item), then cancel all the dialogs that will popup offering you to handle it for you, then right click your database from your project explorer, go to properties and select Build Action: Embedded Resource.
Then use the method below to dump your database into a temporary file, which you can create by calling Path.GetTempFileName.
internal void CreateBlankDatabase(string destFile)
{
using (Stream source = new MemoryStream(Properties.Resources.MyEmbeddedDatabase))
using (Stream target = File.Open(destFile, FileMode.Truncate))
{
source.CopyTo(target);
}
}
(Note that MyEmbeddedDatabase would be your embedded database name). Then use your temporary file name in your connection string. Make sure you delete your temporary file after you're done. Also, as other said, you won't be able to modify and save any data.
No it shouldn't be done. How would you send someone and update to the .exe file without them losing their data? Keep it separate.
You need to have a way to manage how your applications installs and the file location in your connection string(s). There could be a \Data subfolder in your app folder with the .accdb file(s) in it.
You probably can't achieve what you want with an access database as an embedded resource, but you effectively get the same result by wrapping all your files in another executable app.
When you run the wrapper application, it extracts the "main" C# app, database file, and an updater app (more on this below) to the temporary files folder and runs the main app.
When the main app is closed, it runs the updater app, passing in the paths to the database file and original wrapper application. The updater app updates the wrapper application file with the changed database file. It then finally deletes the database main app and database file from the temp folder. Unfortunately, the updater app can't delete itself, but you could work around that by adding a command to the runonce section of the registry to delete the updater app on the next reboot.
Instead of figuring out how to extract and insert embedded resources, consider having the wrapper application as a compressed, self-extracting executable (like a self-extracting zip or rar file). Here's a codeproject article that describes how to turn a .Net app into a compressed, self extracting exe.
Access requires to be able to read and write to the file. The OS will lock the exe when it is run so that it can't be changed while in use. This along will cause it to not work, not to mention that Access simple wouldn't be able to read the exe as it is expecting a different file format.
Hello guys I think the question i asked in the previous post is unclear OK fine. i am explaining in brief.
for example.
I have a form where i have placed one textbox and command button.
I have fired a event when i click the button the text under the textbox change to "hello" ok fine.
what is my problem is..
the application is created and I published ok.
After some week I thought I want to update my application. where in the place of "hello" I want "hi". I know that we can compile the whole project and publish it.
but I don't want my whole application to be updated.
for example.
What antivirus company do they have a definition file where they only update the definition file not the whole application. after the update it applies to whole application.
I want my application also to do same process like antivirus company do.
You should read that "Hello" from a content file (XML). Then you can just push out the new file.
Use a configuration file. You can add an application.config (or if you're developing a web app, web.config) file to your primary project. Within this configuration file, you can define AppSettings (which are built-in, usually simple and atomic string or number fields that the application will need), ConnectionStrings (which specifically provide information applications will need to connect to a database), or custom configuration sections (used for more complex, related sets of data that are loaded into custom classes you define, such as a basic company profile). Within your code, you access AppSettings by using the static ConfigurationManager.Appsettings[] collection; you tell it the name of the setting you defined in the file, and it returns the value (or null, if it can't find the setting you defined).
Related, but different, is the use of Resource files. Resource files usually contain a dictionary of location-specific data used by the UI, such as text strings, icons and images. Actual resources can be compiled into one big file, or resource files can be a list of paths and filenames to the actual resources. You can use resource files to create different "skins" for your application to be used by different companies by referencing images to use for UI elements, or to translate labels and other text on your application's UI. Resource files are accessed through a ResourceManager; you tell it where the resource file is, and it will load the information into a similar "dictionary"; you then tell it the name of the resource and you get the resource back.
For your specific question, I'll answer the same thing as Henk. But, I think that your real question is "How I do create patch in .NET".
You can check this link:
How can I patch .NET assemblies?
You could design your application to use plugins. This way you only have to update a plugin and not the whole application.
if you want to create a patch for asp.net application , first of all , you have to deploy your project with Web Deployment Project.
then choose Create a separate assembly for each page and control output in output assemblies tab and re-build your solution .
the result of deployment is bunch of DLL which mapped to each page or control.
Now if you changed one page's data (in code behind) , you need to deploy your project again but in this case you can just upload the changed dll file.
I am creating an application that uses a certain file format as its data source. I want this application to open whenever the user double clicks on this file, like how MS Word will open when a user double clicks on a Word document. How do I accomplish this? Also how would I populate the data fields using the file that the user selected. Would I use args[] from the program.cs class? I am using c# to code this application.
N.B. I want this association to be made when the application is installed on the host machine without the user doing anything.
FIRST, you need to set up file association, so that your file type is associated with your application and opening the file type will run your application.
You can do the file association programatically, there is some detail here as mentioned:
http://www.codeproject.com/KB/dotnet/System_File_Association.aspx
You can also do it via your Setup project for you application if you have one. This is an easier path for "newbies". Details for using visual studio to get the setup project to add the file association and also set the icon for the file are here:
http://www.dreamincode.net/forums/topic/58005-file-associations-in-visual-studio/
Otherwise if you use InnoSetup, Wix etc then I suppose you could just see instructions for those installers to create the association for you.
SECOND, you need to have your application accept command line arguments. The opened file(s) is(are) passed as a command line argument(s). You need to process the arguments to get the file path/name(s) and open the given file(s). There is a nice description of this here with code:
C# Command Line arguments problem in Release build
In your case, rather than MessageBox.Show(s) in the form shown handler, you would call your bespoke argument parsing method.
For a simple application which only accepts files names to open as arguments, this could be as simple as
foreach (string filePathName in Args)
DoNamedFileOpen(filePathName);
Your code can also have a method that might extract from the file the values for the datafields you are interested in etc.
This is a nice simple approach to the issue of have file associations set on installation of your application, with icons, and having your application handle the opening of those files.
Of course, there are plenty of other options, like run-time file association (asking the user if they want the association), detecting "broken" associations, etc.
This question is a long time here but I hope this is useful for new searches
See this. Or this if you want API information.
ClickOnce supports file associations as of .NET 3.5 SP1, too. In the project's properties, switch to the Publish tab and click the Options button. There's a File Associations section in that dialog that allows you to specify file extensions, descriptions and custom icons.
First, you have to associate the filetype extention with your executeable. On Windows you do this via the registry (search "filetype association windows"). In this question you find some interesting hints: Filetype association with application (C#) Script to associate an extension to a program
Your program has to react on the command line arguments or parameters. In Java, it is indeed the string array of the main method. I would gess, it's the same in C#.
If you don't need to do it pro programatically, right click on the icon, click open with ..., then select 'always use this program ...'.
This is something usually handled by your setup program .. I've used INNO setup for example, and it's trivially simple to arrange for it to adjust user's registry to launch your app when associated file extension is double clicked/opened. It'll even take care of MIME types for you as well as clearing these things on uninstall, which is a very nice thing to do
I managed to solve this issue. I used WIX to create an install file and asked it to associate the file with the application when it installs.