We inherited some C# code as part of a project from another company which does URL redirects that modifies the existing query string, changing values of items, adding new params, etc as needed. The issue however is that the code is buggy at best, and ends up duplicating items in the query string instead of updating them properly. The code works on the first pass but on additional calls the duplication issues become apparent.
Ex: MyPage.aspx?startdate=08/22/09&startdate=09/22/09
Instead of duplicating the item it needs to be either updated with the new value if it already exists, or added if not there already.
Is there a C# class or set of functions for handling query strings, allowing a simple means to access and update/add parameters that gets around these issues instead of the blind add approach that seems to be in use now with the code? This needs to be able to handle multiple parameters that may or may not exists at all times and be added and updated on subsequent calls.
We would sooner use existing logic than recreate something if possible so as to get this resolved quickly in a semi standard way for future maintainability and reuse.
Yes I would suggest converting the querystring to a collection by using HttpUtility.ParseQueryString()
You can then find/add/update/replace values directly in the collection, before re-creating the querystring from this collection.
This should make it easier to spot duplicates.
You can access and manipulate all values of your Querystring through the Request.QueryString collection. Here's a link.
this seems a basic design problem.
instead of updating the current query string, what SHOULD be done is simply adding all the parameters to the base at every time.
sure, you CAN update it, but (pseudocode)
if querystring exists
then update query string
else
add query string
will get crazy when you start using more than 1 variable.
redesign would be best, effort allowing.
The WCF REST Starter Kit available on ASP.NET also include a new "HttpQueryString" helper class that will most likely be included in the .NET 4.0 time frame into the base class library.
See an excellent screencast on how to use this utility class here:
http://channel9.msdn.com/shows/Endpoint/endpointtv-Screencast-HttpClient-Query-String-and-Form-Input-Management/
Marc
Related
I've been trying to use the TSqlModel method DeleteObjects to programmatically remove certain users from a Database project. The problem is that when I call the method, the user remains in the model. I wonder if I am calling the method correctly. Here's something close to what I am doing:
modelFromDacpac.DeleteObjects(#"DOMAIN\user");
When I run the following code to see if it's really gone, the user is still there!
var tst_delete= modelFromDacpac.GetObjects(User.TypeClass, new ObjectIdentifier(#"DOMAIN\user"), DacQueryScopes.Default).FirstOrDefault();
tst_delete is non-null and has a name that matches "DOMAIN\user".
Any idea what I'm doing wrong?
Prior to the DeleteObject method call, I insert the following line - where the sqlobj object is a TSqlObject referring to the user I am trying to delete
//For some reason, the logins aren't scripted objects within the DACPAC, and so cannot be deleted using the DeleteObjects method - or maybe they simply cannot be found.
modelFromDacpac.ConvertToScriptedObject(sqlobj, "DOMAIN_user.sql");
Then I call the DeleteObject method as follows:
modelFromDacpac.DeleteObjects("DOMAIN_user.sql");
I'm not sure why this works, but it does. My guess is that the DeleteObject method is pretty picky about how and where it expects to find objects. Or, maybe some objects, like users, are stored in some non-standard fashion which prevents DeleteObjects from finding them. Whatever the reason, but explicitly converting the user to a scripted object with a given name, and passing that given name to the DeleteObjects method, it works.
I am a little concerned that I do not know why it works. The other concern is that it doesn't show up in the official documentation of the TSqlModel object:
https://msdn.microsoft.com/en-us/library/microsoft.sqlserver.dac.model.tsqlmodel_methods(v=sql.120).aspx
But it does work. At least, so far.
DeleteObject caught me out the same way :) - it only deletes scripts added using AddOrUpdate when you also pass in a script name and Delete uses the same script name.
What you need to do is create a new model and add in everything except the things you want to delete.
Why do you want to delete a login? If you don't want it to be deployed you can use a deployment contributor like my one here to exclude the login at deployment time:
https://the.agilesql.club/Blogs/Ed-Elliott/HOWTO-Filter-Dacpac-Deployments
Ed
This is a contrived example however I have simplified it for ease of explanation.
Please see my update at the bottom before investing too much of your
time!
Background
I have some (a lot of) code that ordinarily queries my DB as follows:
SELECT name FROM sites where IsLive=1;
My challenge is to, under certain conditions, return the full list of sites, essentially
SELECT name from sites;
I do not wish to modify the actual C# code issuing the SQL (although I can do if I have to in order to achieve my goal which is purely for demonstration purposes).
Therefore in order to leave as much untouched as possible my thoughts are to insert a database-proxy-view called site that returns the data dependent on a control variable
Method
Rename existing site table to site_table
Create a new view named site that the C# code now unknowingly targets and which returns the (possibly filtered) details from site_table according to the control variable value (Note a limitation on variables in views meant I had to create a function in order to demonstrate this - see http://dev.mysql.com/doc/refman/5.7/en/create-view.html wrt error 1351)
Changes made
ALTER TABLE site RENAME TO site_table;
CREATE FUNCTION controlVariableFn() RETURNS VARCHAR(16) RETURN #controlVariable;
CREATE OR REPLACE VIEW site AS SELECT * from site_table WHERE (IsLive = 1 OR controlVariableFn() = 'SHOWALL');
The above statements are ugly but achieve the result I want, however my problem is to dynamically pass through controlVariable without changing my main SQL queries being sent.
My Question
Is there a way to (ideally as I am creating my connection object) define the controlVariable outside the actual SQL to be executed but which the View can still access similar to the above as though it had been supplied as a regular user variable parameter to the query?
so the code would look something like
var connectionString = "Server=localhost;User ID=un;Password=pw;Database=dbname;....";
DbConnection db = new MySql.Data.MySqlClient.MySqlConnection
(connectionString, "controlVariable=SHOWALL");
var results = db.Query<Site>("SELECT * FROM site;");
(I understand that this would not be a smart permanent solution)
Update
My preferred solution as outlined above will not work for me as once I get into my data access layer as the results set will
essentially be filtered again back to the original set. There are some circumstances where it
could work; it would depend on the SQL issued (e.g. when collapsing a
results set down instead of trying to expand a results set as I was
trying to do here).
In that regard I am no longer looking for an answer here but will leave it for posterity as a preferred option and as per the guidelines - thanks anyway.
If you do not want to edit the c# code then the variable will have to be stored in the database although i am not sure how you will not edit the code.
If you are willing to edit the code then you can access a secondary configuration table which will have the settings that you would like the user to pass to the view. take this and allow the user to select which they want and then pass it to the view through the application.
I realize that handcrafting SQL statements is evil. I also realize that the spontaneous answer of everyone seeing this post will be "Use parameters". I have found several occurences of similar questions around here, but I can't find out how they apply to my specific problem.
I use System.Data.SQLite with C#. I want to dynamically create a VIEW, say listview_asdf which I then can access inside a library with simple SELECT * FROM listview_asdf statements. That library uses loads of automatically generated statements for accessing my view.
Problem is, at one point I need to create a view like this:
CREATE VIEW listview_asdf AS SELECT * FROM tbl_asdf WHERE id IN (1,2,3)
not knowing how many and which parameters I have in the IN() list. Actually, the list will be different each time I use it (I delete the views in their Dispose() methods). Creating the view does - as far as I understand the relevant google result - not allow to use parameters.
So, I need to take an arbitrary-length array of parameters (easy) and write the CREATE VIEW statement with an IN (...) clause. Here, I need to insert the parameter values. This is no problem in case of integers, as shown above, but for strings or other types (System.DateTime comes to mind) I need some kind of escaping.
Else, I need some way of getting around the necessity of escaping. I don't know of any solution to either except the ominous
sql = sql.Replace("'","''");
which, as User Aur Saraf points out here, is a sure way of losing my job (which I do like).
Any ideas for a way out?
Task:
Rip through all the code in the entire solution and wrap all webservice method-calls in another ws method-call that accepts a GUID (it's a login scenario)
Background :
Hundreds of web services, add token security. As explained to me when I was assigned to the task, we do it this way because if, in the future , some changes to security etc have to be made we can just do it in the WrappermethodClass in stead of having to change hundreds of web services
Tried and failed :
Find all references : too much data , returned more than 1000 hits , most of which are useless as they're only object references.
Rename WS so all references beak, build the project I'm working on and fix as I go : works well with the services not integral to the functionality but as soon as I do it with an important one it's like I shot the Solution through the brain, everything's f****d and and VS just gives up trying.
Current Solution :Open all relevant docs, Find ,select All Open Docs, skip through.
Question : How do I do this as efficiently as possible?
Code (before) :
wsGeneric wsGen = new wsGeneric();
wsGen.DoSomething();
Code (after) :
WrapperMethodClass.DoCheck takes params of (Action, GUID),
wsGeneric wsGen = new wGeneric();
wrapperMethodClass.DoCheck((g) =>
{ wsGen.UserInfo.token = g.ToString();
wsGen.DoSomething();
},Shell.token.Value);
Don´t you have some sort of interface or class where you changed the method signature already?
If you changed your webservice and your Code still compiles i´d say you did something wrong or i don´t understand the question.
Update:
I still don´t get it.
I think you have these options:
Change the method signature (all calls should be broken now, fix all the errors vs gives you and you should be done)
Find all references (of the method, not your webservice-class) and change the calls
If above isn´t possible use "Find in Files" and search for the method-name
If all your webservices inherit from an interface or base class you can refactor this method to add a parameter, all inheriting classes will also have the parameter.
If you pass a login object to each webservice, you can add a GUID element to this object and you're done.
It would be a lot easier if you showed us some code, some function interfaces that you have to change and how.
A better solution may be to just use PostSharp to add the checks to your services. This will solve your business problem (you only need to update your aspects) and is much less error prone then your current approach since you don't have to wory about some new developer forgetting to make the call to DoCheck.
Not having to find all references is a side benefit.
I am writing a program that needs to read a set of records that describe the register map of a device I need to communicate with. Each record will have a handfull of fields that describe the properties of each register.
I don't really need to edit or modify the data in my VB or C# program, though I would like to be able to display the data on a grid. I would like to store the data in a CSV file, or perhaps an XML file. I need to enable users to edit the data off-line, preferably in excel.
I am considering using a DataTable or a Collection of "Register" objects (which I would define).
I prototyped a DataTable, and found I can read/write XML easily using the built in methods and I can easily bind to a DataGridView. I was not able to find a way to retreive info on a single register without using a query that returns a collection of rows, even though I defined a unique primaty key column. The syntax to get a value from a column is also complex, though I could be missing something on both counts.
I'm tempted to use a collection of "Register" objects that I can access via a unique key. It would be a little more coding up front, but seems like a cleaner solution overall. I should still be able to use LINQ to dataset to query subsets of registers when I need them, but would also be able to grab a single field using a the key value, something like this: Registers(keyValue).fieldName).
Which would be a cleaner approach to the problem?
Is there a way to read/write XML into a Collection without needing custom code?
Could this be accomplished using String for a key?
UPDATE: Sounds like the consensus is towards the Collection of register Objects. Makes sense to me. I was leaning that way, and since nobody pointed out any DataTable features that would simplify acessing a single row, it looks like the Collection is clearly the way to go. Thanks to those who weighed in.
I would be inclined not to use data sets. It would be better to work with objects and collections. Your code will be more maintainable/readable, composable, testable & reusable.
Given that you can do queries on the data set to return particular row, you might find that a LINQ query to turn the rows into objects may be all the custom code that you need.
Using a Dictionary<string, Register> for look ups is a good idea if you have a large number of items (say greater than 1000). Otherwise a simple LINQ query should be fine.
It depends on how you define 'clean'.
A generic collection is potentially MUCH more lightweight than a DataTable. But on the other hand that doesn't seem to be too much of an issue for you. And unless you go into heavy reflection you'll have to write some code to read/write xml.
If you use a key I'd also recommend (in the case of the collection) to use a Dictionary. That way you have a Collection of the raw data and still can identify each entry through the key in the Dictionary.
I usually use datatables if its something quick and unlikely to be used in any other way. If it's something I can see evolving into an object that has its own use within the app (like your Register Object you mentioned).
It might be a little extra code up front - but it saves converting from a datatable to the collection in the future if you come up with something you would like to do based on an individual row, or if you want/need to add some sort of extra functionality to that element down the road.
I would go with the collection of objects so you can swap out the data access later if you need to.
You can serialize classes with an xml serializer and defining a Serialize attribute or something like that (it has been a while since I done that, sorry for the vagueness). A DataSet or DataTable works great with XML.
Both DS and DT have ReadXml and WriteXml methods. XML must be predefined format, but it works seamlessly.
Otherwise, I personally like collections or dictionaries; DS/DT are OK, but I like custom objects, and LINQ adds in some power.
HTH.