What is the best deployment approach for WPF applications with local database? - sql-server

I want to make a WPF application that exists in one directory including all files that it needs: .exe, .mdf database, .xml config files, etc.
the application should work no matter what directory it is in so that it supports this scenario:
person 1 executes the application in c:\temp\wpftool.exe
the application reads and writes to the c:\temp\wpftool.mdf database
person 1 zips up that directory and sends it to person 2 via e-mail
person 2 unzips it to c:\Users\jim\documents\checkout\wpftool.exe, the application reads and writes to the same database in that directory (c:\Users\jim\documents\checkout\wpftool.mdf)
person 2 zips the directory up again and sends it back to person 1 to continue making changes on it
What is the best way to create a WPF application that supports the above scenario?, considering:
there should be no hard-coded database connection strings
what is the best deployment method, click once? or just copy the .exe file out of the /release directory?
reasonable security so that users have to log in based on passwords in the database, and if a third person happens to intercept the e-mail, he could not easily look at the data in the database

Some points on the database side:
Assuming the "New user" already has SQL installed, they'd need to attach the (newly copied) database. Besides having sufficient access rights to attach a database, your application would need to configure the call to include the drive\folder containing the database files. If your .exe can identify it's "new home folder" on the fly, you should be able to work that out.
Define "reasonable security". Any database file I get, I can open, review, and ultimately figure out (depends on how obscure the contents are). Can you obfuscate your data, such as using table "A" instead of "Customer"? Would you really want to? The best possible security involves data encryption, and managing that--and in particular, the encryption keys--can be a pretty advanced subject, depending on just how "secure" you want your data to be.

For the database, I would look into using the "user instance" feature in SQL Express. Combined with the |DataDirectory| substitution string support it makes it very easy for your application to get hooked up.
In all honesty I have not deployed a ClickOnce app leveraging this approach myself yet, but I just thought I would bring it to your attention because it's what I would look into myself if I was building something like you described.

Related

C# SQL connection string best practice

I have a winforms application that connects to a database with a connection string and a generic user
"Database=DBADAS;Server=TMT123\\SQLEXPRESS;User ID=user; Password=*****;
After connecting into the database with a login dialog, we check if the user and password are existent in the user table from the database.
My question is now if this is a good practice? because basically in the connection string there is every information needed to crack the server.
There are a few ways to go about this safely. Since it's a Winforms app and not a web application, most of your security risks involve someone already in your network peeking at the connection string. This adds a layer of security in and of itself.
1. Hardcoded
You can hardcode the connection string that fetches the users into a DLL and make your application depend on that DLL. I only suggest this because it sounds like the "generic user" password is permanent; otherwise, you'd have to recompile code every time you changed the password, then deploy again. This is very secure, however, as the value isn't stored in plain text.
2. App.Config
You can stick it in a configuration file. Within a secured network, this is probably the most versatile option, as you can store multiple strings and easily update them without updating the full application. This goes well alongside settings like a "DebugMode" setting, etc. Using App.Config or another XML file is ideal, but you can roll a quick and dirty .txt file, too.
3. Database
Probably the most secure way of all, as you can encrypt your database and code your programs to fetch their connection strings and login information from that database by using an unrelated login. This allows greater control over what can be reached by the application when a user has not yet logged in. It also prevents the software from operating outside of the network, which may be desirable.
4. Internal API
Having a separate application serve this data divorces user capability from your concerns, as the API and your app can exchange verification keys to see if your app even has permission to try to connect. This is my personal favorite, but obviously the most work to set up.
5. Registry Entry
Depending on how you have this installed, it may work well to embed the tokens you need in the Registry. This guarantees the app requires admin permissions to install, and allows you to use Windows security to restrict access to the hive.
Again, since it's an internal non-web app, I wouldn't worry too much about the plain text of the connectionstring; if someone has gotten this far into your network, chances are you have much bigger problems already. I wouldn't leave it floating as a plain text file in a local directory, but any degree of security above that is probably acceptable for your purposes.
Encrypting Web.Config
Open Command Prompt with Administrator privileges
At the CommandPrompt, enter:
cd C:\Windows\Microsoft.NET\Framework\v4.0.30319
In case your web Config is located in "D:\Articles\EncryptWebConfig" directory path, then enter the following to encrypt the ConnectionString:
ASPNET_REGIIS -pef "connectionStrings" "D:\Articles\EncryptWebConfig"
Use Aspnet_regiis.exe tool with the –pef option and specify the application path as shown above.
Note: The parameter "connectionStrings" is case sensitive.
For Winforms: You need to rename your app.config to web.config encrypt it by using steps 1 to 3 and again rename it to app.config.
Reference: https://www.codeproject.com/Tips/795135/Encrypt-ConnectionString-in-Web-Config

Informix-SQL (SE) on the cloud with WinTerm thin clients

I have several customers, each running a customized version of my ISQL (SE) desktop app. I would like to replace their desktop app with thin client WinTerm's, connecting to the cloud (My ISQL app on an SuSE Open or RedHat server). If this can be done, I would like for each customer to use one standardized version of my app to simplify updates and support. However, I'm not sure what's the best way to design the database. Should each customer have their own database.dbs (DBPATH=) or is there a better design?
You have two options, one of them that you've already considered:
Each customer has their own database with the standard name.
Each customer has their own database with a separate name for each.
The advantage of option 1 is that your existing code would work substantially unchanged; you'd simply have to ensure that the setting of DBPATH is correct for each customer. The downside is that you need to create a separate directory for each customer too. However, this has its merits; you can probably more easily keep Customer A from seeing any of the files generated by Customer B (and vice versa) if each customer has their own separate home directory, and their database is located in that directory.
The advantage of option 2 is that you can put all the customers' databases in a single directory. As mentioned, this is apt to make it easier for Customer A to see stuff that he should not see that belongs to Customer B. You would also have to ensure that you override the default database name every time you run a command - whether that's sperform or sacego or anything else.
Between the two, I would go with option 1 (separate databases with common name in different directories), with rigid walls between customers. Each customer would have their own user name and group, and the permissions on the directories would avoid public access of any sort. They can all still use a single INFORMIXDIR and your associated forms and reports.

SQLite vs.SQLCE Deployment

I am in the process of writing an offline-capable smartclient that will have syncing capability back to the main backend when a connection can be made. As a side note, I considered the Microsoft Sync Framework but since I'm really only going one-way I didn't feel it would buy me enough to justify it.
The question I have is related to SQLite vs. SQLCE and ClickOnce deployments. I've dealt with SQLite before (impressive little tool) and I've dealt with ClickOnce, but never together. If I setup an installer for my app via ClickOnce, how do I ensure during upgrades the local database doesn't get wiped out? Is it possible to upgrade the database (table structure, etc. if necessary) as part of the installer? Or is it better to use SQLCE for something like this? I definitely don't want to go the route of installing SQL Express or anything as the overhead would be far too high for what I am doing.
I can't speak about SQLLite, having never deployed it, but I do have some info about SQLCE.
First, you don't have to deploy it as a prerequisite. You can just include the dll's in your project. You can check this article which explains how. This gives you finite control over what version is being used, and you don't have to deal with installing it per se.
Second, I don't recommend that you deploy the database as a data file and let ClickOnce manage it. When you change that file, ClickOnce will publish it again and put it in the data directory. Then it will take the previous one and put it in the \pre subfolder, and if you have no code to handle that, your user will lose his data. So if you open the database file to look at the table structure, you might be unpleasantly surprised to get a phone call from your user about the data being gone.
If you need to retain the data between updates, I recommend you move the database to the [LocalApplicationData] folder the first time the application runs, and reference it there. Then if you need to do any updates to the structure, you can do them programmatically and control when they happen. This article explains how to do this and why.
The other advantage to putting the data in LocalApplicationData is that if the user has a problem and has to uninstall and reinstall the application, his data is retained.
Regardless of the embedded database you choose your database file (.sqlite or .sdf) will be a part of your project so you will be able to use "Build Action" and "Copy to Output Directory" properties of that file to control what happens with the file during the install/update.
If you choose "Do not copy" it will not copy the database file and if you choose "Copy if newer" it will only copy if you have a new version of your database file.
You will need to experiment a little but by using these two properties you can have full control of how and when your database file is deployed/updated...

Should data files be stored on the same computer (server) the database is stored in?

Currently in our research group, we have many "data files" stored on three servers and a couple of personal computers running different operating systems.
We want to build a database, which would store some information in addition to the URLs of those various "data files". My question is, do we have to copy all the data files and put them in a directory in the same server the database is in? Or can they be left as they are on the different computers? If the second case is ok, what would be the format of the url of the "data files"?
It really depends on what your intended goal is and what your current setup is like
If the files are currently sitting somewhere on the network, and you need a path that the application can use to access them, you just need to store the network path (\\server\share\file for Windows environments) in the database, then read it and access that path to access the files. You'll need to make sure everyone has read access to them.
If the files are currently accessible through a website URL, internal or external, then again, you just need to store that URL (or some portion thereof) (http://mywebsite.com/myfile or http://servername/myfile) and access that.
If either of the above are not currently true, but you want them to be, then you'll need to set up a new share/webserver and put the files there. There's no requirement that this be the same server as the database, but it'd make for better backups if it was.
If you want the files themselves to be in the database, you should check out Bob Fanger's link.
Not sure what you're asking here but...
If you want your database engine to read files filled with data, it probably doesn't matter where they are stored - though this may depend on the database you are using. Are you using MySQL? MS-SQL Server? Oracle?
Many database vendors provide relatively easy-to-use admin tools that would let you choose a file to be loaded, and usually the file chooser dialoge lets you browse networks so you could load a file over the network. Details on how to do this vary so consult the manual for your database engine for loading data from a pre-existing file.
Be aware that if the database is on Computer A and the data is being loaded from Computer B over the network, it will probably be slower than if the data was on the same computer as the database.
It doesn't really matter if the files are stored outside the database anyway.
See Storing Images in DB - Yea or Nay? for more thoughts on that one.
If the files accessible by an url, you can store that with the meta data, like
http://server1/folder/file.ext, file://\server1\folder\file.ext or "file://P:\folder\file.ext"
Things to consider:
Backups
Performance
Synchronisation between the meta-data and the data

Access 2007 to SQL server file upload?

I have an Access 2007 database with an attachments facility. Currently the client may upload files locally but the files cannot be accessed elsewhere. I have been able to carry out a similar operation when developing on a web based system however I cannot seem to do it on an Access 2007 database and I am unsure as to whether it is even possible. Basically the system needs to connect to the SQL server online and upload the file although the database is not online itself. I would be grateful for any pointers!
I have faced this situation. Here are your choices:
Use Access attachment field in a shared ACCDB -- won't work "online" very well, but you could park the ACCDB on your LAN and make it a separate back-end ACCDB shared by all. Your post didn't say whether your users are either local or "online" -- and whether "online" meant web.
Use VarChar(Max) (aka BLOB) fields in SQL-Server to store the attachments. But, you can't populate these easily from Access. Assuming you control the server where SQL-Server is running, you can use ADO in Access to upload a VarChar(Max) using the bulkinsert T-SQL command. This works pretty well and it's easy.
Create an upload web page. Use iExplorer automation (i.e, create an iExplorer object) in VBA to navigate to that page, fill it in and press the upload button. For security reasons, you cannot use automation to fill in a file upload control, but you can use sendkeys. This doesn't work perfectly -- sometimes you have to repeat the process once or twice, but it works pretty well if it's invoked by a user who can validate it's working. This is what I did -- easiest solution.
Best solution probably is to create a web service using WCF to handle the upload. There are plenty of posts on how to encode and decode byte arrays to store files as VarChar(Max). It works extremely well. Unfortunately, Access cannot directly consume web services as far as I've been able to tell, so you would have to write a small vb.net program to do this and call it from Access.
You could store the files/attachments outside of SQL/Server - just on the server, and store only the links/URL's for those files in Access. You could make each one launchable. This is easy but harder to control the security.
You can use Sharepoint to store/share the attachments. That can work pretty well depending on the size of the attachments and your connectivity. It's built to support this.
Access allows multiple attachments in one record. SQL/Server doesn't support this. So, if you can split your ACCDB into a front-end for the programs only and back-end ACCDB that is sharable by your users to contain the data/attachments, that is by far the easiest answer.

Resources