How can I set read-only DB Connection Strings? - c#

I've got a DB connection string that I'm creating in my web.config:
<connectionStrings>
<add name="DBConn" connectionString="Data Source=<db svr>;Initial Catalog=<dbname>;Integrated Security=True" providerName="System.Data.SqlClient />
</connectionStrings>
or
Data Source=<db svr>;Database=<db name>;User ID=<uname>;Password=<pword>;
but I need this connection to be read only. I've defined all my linq objects with only gets on their properties, and none of my (MVC) repository classes have .SubmitChanges() methods in them so I'm 99% sure the system can't update this DB, but I would also like to set my DB connection to be RO if at all possible. I realise that ideally this should be done at the SQL server end and the user should be made RO, but that (for various reasons, out of my control) can't be done, so I wanted to lock down my connection as the app mustn't write to the DB.
Is there a "readonly" parameter I can apply to the connection string so that it would throw an error or discard the data if any updates were attempted?
Just to reiterate (the 1st answer I had, when asking this, on another forum was "change your DB credentials") I cannot, in any way, change the DB access credentials, these are read-write, and any attempt to change them (currently) crashes the SQL Server database.
This is not my problem, and I can't look at resolving that issue, so that's why I want to look at making the DB connection read-only as it absolutely, positively can't change the DB data.

No, there is no way (that I know of). Unfortunately for you, the right way to do it would be to change the grants of the current user, or create a new user with only select privileges. I realize this is not the answer you are looking for but having a Sql Server that crashes when you try to change things in it seems to be a problem that is really worth looking into. Is it because you are using the "sa" account to connect? If so you should create another user and grant the appropriate permissions to the new user.

What you have under your control is classes to acces code (L2S).
I suggest to override in a partial class the SubmitChanges for your datacontext in order to do nothing ( or even throw an error!) (or implementing all extensibility methods InsertObject, UpdateObject or DeleteObject that belong to your datacontext)

It really depends on what database and DB provider you are using. Some allow readonly access on the connection string, some don't.
For example:
SQL Server 2005 CE, when using the .NET Compact Framework Data Provider for SQL Server Mobile, has a possible File Mode=Read Only; parameter. (see on connectionstrings.com).
SQL Server 2008, doesn't.
You can check more on connectionstrings.com.

there's nothing you can do at the connection string level that prevents writes other than change the user - which you've already said you can't do.
In that case you simply have to do the utmost in your code to prevent any writes; i.e:
any public layers should not expose update/delete/insert semantics or whatever.
make any data layer classes sealed so that they cannot be overriden
However, there's still nothing stopping a programmer from coming along, ripping out your connection string, and sticking it inside their own Connection to perform writes.
You could, therefore, move the connection string somewhere else that only internal code knows how to access (it's still going to be text-file driven, though, don't use a code constant!); it's still not stopping anyone from using it - but it makes it a lot harder.
(added) I should explain why it does not protect it.
Leaving aside that the source of the connection string itself is likely to be accessible, even by protection with encryption libraries etc, there's nothing stopping me reflecting to your code and calling it, apart from trust levels. You might choose to go the whole obfuscation route to prevent me from deconstructing your code; but surely this level of paranoia is not required within your development house?
Ultimately, though, because it's 'SEP' (somebody else's problem) as you put it, and you have no control over that - if anybody asks you why, despite your best efforts, you can't guarantee that no writes will be performed, you can safely blame that 'somebody else'.

Related

Desktop application which can work offline when no connectivity with SQL Server

I am designing a WPF desktop application and using Entity framework Code First to create and use SQL Server Database. My database will be hosted on One Server machine and will be running 24*7.
I want to provide a feature, where you can modify data offline(when you have no connectivity with SQL Server DB) and Save it somehow. And whenever your application will find connection with SQL Server, all changes can be moved to SQL Server DB.
Is there any way to achieve this by using Entity Framework ?
I want to emphasis on the part that I am using Entity Framework. Is this type of functionality already implemented by EF?? Or I have to do it manually, like have to write that in any file system and then manually merge it later to DB ?
You could figure out the specific exceptions that are generated when the SQL Server connection is lost, and embed your calls in try-catch blocks. If the server is offline, then in your catch block, pass the entity to a method that serializes the entity to JSON and saves it to the hard drive in a special directory or something. On your next successful query, check that directory to see if there are any saved entities that need to be saved.
Be specific with your catches - you don't want unrelated exceptions to trigger this code.
Some things to keep in mind - what if somebody else changed the data in the meantime? Are you intending to overwrite those changes? How did you get the data which needs to be saved in the first place if you are offline?
As long as you have all data loaded into DbContext/ObjectContext you're free to amend those data anyway you want. Only when SaveChanges() is invoked, the connection is really needed.
However, if you're going to load everything into the context, you seem to reimplementing DataSet functionality, which, in addition, allows for xml serialization/deserialization of the changes, so the changes can be even saved between sessions.
Not as trendy as EF, though :)
While I have never tried this with SQL-based data I have done it in the past with filesystem-based data and it's a major can of worms.
First, you have to have some means of indicating what data needs to be stored locally so that it will be available when you're offline. This will need to be updated either all the time or before you head out--and that can involve a lot of data transfer.
Second, once you're back online there's a lot of conflict resolution that must be done. If there's a realistic chance that someone else might have changed the data while you were out you need some way of detecting the conflict and prompting the user as to what to do in that situation. This almost certainly requires a system that keeps a detailed edit trail on every unit of data that could reasonably be updated.
In my situation I was very fortunate in that it was virtually certain that if the remote user edited file [x] that overwriting the system copy was the right thing to do. Remote users would only be carrying the files that pertained to their projects, conflicts should never happen. Thus the writeback was simply based on timestamps, nothing more. Data which people in the field would not normally need to modify was handled by not even looking at it, modified files were simply copied from the system to the laptop.
This leaves the middle step--saving the pending writes. I disagree with Elemental Pete's answer in this regard--simply serializing them and saving the result them does not work because what happens when you read that data back in again? You see the old copy, not the changed copy!
My approach to this was a local store of all relevant data that was accessed exactly like the main system data was, all reads and writes worked normally.
Something a lot fancier might be needed if you have data that needs transactions involved.
Note that we also hit a nasty human problem: the update process took several minutes (note: >10y ago) simply analyzing what needed to be done, not counting any actual copy time. The result was people bypassing it when they thought they could. Sometimes they thought wrong, oops!

multi-user MS Access Database- how to lock completely

We have an MS Access database (accdb) out on our network, that multiple users will edit & read by means of a .NET application. I am aware that a server db such as SQL Server would be the best choice for this situation, but currently that's out of my hands.
The .Net application will use both ADO.Net (ie OleDBConnections) and the tools inside the Microsoft.Office.Interop.Access.Dao namespace to connect to the database.
I have read a few articles and posts about multiple users connecting to Access, and there seems to be some confusion and differing opinions about Access's capabilities in this regard. How/can I achieve the following in my application:
Establish connections to write to the database, that will lock the entire database (all records and tables) until the connection is ended. If other users attempting to write simultaneously are halted by an exception, that is okay.
Establish connections designated as read-only, that have no conflicts with any other user's actions.
Thanks.
To open a ACCDB in exclusive mode you need to add this key/value to your connection string
Mode=Share Exclusive;
This will block other user to connect to the same database until you close and dispose the
connection that opens the database in this way.
If I remember well, the possible values (pretty self explanatory) for the Mode keyword in the JET connection string are
Mode='Read';
Mode='Write';
Mode='ReadWrite';
Mode='Share Deny None';
Mode='Share Deny Read';
Mode='Share Deny Write';
Mode='Share Exclusive';
I have tried various combination of the flags above, but I can't find a simple solution that allows a single connection to be opened in ReadWrite while the following connections fall back to Read Only automatically. Probably in your scenario the best path is to have a local connection (not a global one), try to open it in Share Exclusive if you need to write to the database and catch the exception if you cannot open the database giving the user a Retry option. Not an easy path I know. Let's see if a user with a better knowledge of MS-Access could give a more elaborate solution.
I agree with the comment above (and your own assesment) that this is not the best database tool to use in situations of concurrency, however things are a lot better now.
I find this answer well written, comprensive and with a balanced view of the strength and weakness of Access about concurrency issues.

Select databases dynamically

I ran into real brick wall trying to connect to dynamic databases. And I don't know how to achieve this,
Here is my process, I have an application where it needs to be adaptable to changes in the work environment, say If the work places server crashes and they create a new database with the name db_new the application would connect to that instead of the old database name.
I already have a window that displays the databases from the server on a listbox where the user can specify which database to use for the application. But the issue is, how can I save the selected database name so that it can run after the new database is selected? ..
as in the administrator should be able to change the database the application uses if necessary and the application should keep on using that selected database till the administrator changes it back to a new one.
Please forgive if the question a bit vague, I just put it together in the best way I could, any help on this would be really great :)
EDIT:
And I cannot use text files or xml s as the database name the application uses should be stored in a secure manner. :)
First of all, you can very easily use a text or XML file: If you store the information in a file, that can't be downloaded by the user (as I assume you would), this is as safe as it can be: If somebody manages to break into the server and read the file, it's game over anyway.
That said, I would recommend you use MySQL proxy or a similar mechanism and point your WebApp at it - failing over to another database or changing the underlying database could then be handled at the proxy layer without the WebApp even knowing about it: The functionality need not be part of your application and in my book it shouldn't.
You haven't told us the language you are using. Therefore we cannot offer very good suggestions.
My first thoughts:
If this was PHP you could have the general app use something along the lines of,
$db->execute('sql statement here');
and then just have the administrator change the current $db when needed. That way $db->execute() will always be executed on the "current" database.
Edit: This should still work in C#. If you have the functions using the database call a variable that is the current db connection then you should be able to change the db connection to the proper database whenever you need while the rest of it continues running since it's just the same variable.

Switching between databases in C# winforms

I made an application that generates reports based on data from a database.
The functionality of my application is correct, but I have a following problem: my client has 2 identical databases - one for testing and one for actual work he does.
My application should work with both databases (it should have a "switching mechanism"), but I don't know how to implement it.
I know that I could just switch between connection strings but the problem is that in my reports I use datasets that are bound to one database.
Is it possible to fill those datasets with the data from both databases (since the databases are identical in schema, it should be possible), and how would that be done, or do I have to use duplicate dataset/report pairs?
I'm using C# in VS 2010 with SQL Server 2005, and .rdlc for my reports.
Thanks.
Ideally you should should be able to change the connection string in one place and it should affect project-wide.
This will work ONLY IF you get the connection string from one place. Keep it in the app.config file.
See this article to see how you can store and read the connection string from the app.config file.
You've hit upon the reason why people implement the Repository pattern or at least a version of it.
You really need to remove your business logic away from the database, so that it is database agnostic. It shouldn't care where the data comes from only what it is.
From what you' said the implication is that your client doesn't wants more than just a change in the app.config connection string used for database access.
If that is so then, I know that it will entail some work, your best bet is to have a singleton pattern type class to control all data access to and from your data layer.
Using a known inteface you can use a factory pattern to create access to your development or live database at runtime (perhaps based on an app.config setting or even a test class that has no database access at all, but just returns hard coded test data.

Allowing SQL queries that view data not modify it

I am working on an application that will allow users to create queries on their own to view data in their database. However the stipulation is that the application should prevent any modification of the tables and data stored in the database. The Application will be written in C#. Any good suggestions of how this could be done? Possible idea that I have thought of:
Parse SQL to filter for any reserve word that may alter data(i.e. insert, alter, ect)
There maybe a setting that may prevent modification from this applications connection.
Any suggestion to block any changes made from this application to prevent any chance of a user error or attempt to modify tables of data is much appreciated.
You should run your queries as a user that doesn't have write permission.
Any decent DBMS should have these protections already built in (at a per-user level). You just make sure the only access they have is read-only.
Then you don't have to worry about anything that they do. Let them try to insert, update and delete all they want.
It's a basic tenet of databases that they are responsible for their own security and integrity. You never leave that up to an external application since any monkey can write an application to connect to the database that doesn't follow the rules.
This needs to be handled at the user level rather than the query level. When you set up your app, you'll need to make sure that the account used to run the queries does not have any dbwriter permissions.
This is usually handled by giving users access to (non-updatable) views, but not to tables.
IMHO, the best way is to create a user that can only do select on specified tables. And then use that user for connection.

Categories