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
Related
I have tried finding an answer to this question practically everywhere I could imagine, including here on StackOverflow. Unfortunately to no avail. So here it is.
I'm working on an Outlook Add-in (with Outlook 2021), and have developed some code that creates some ItemProperties specifically for use with that add-in. Now, when those properties are created, I can see them when I go to View->Settings->Advanced View Settings->Columns, as illustrated in the screenshot.
Screenshot of User-defined fields in Outlook
In some cases, though, I want to completely delete the properties. And as I know how to do that manually, as pointed out in the figure, I can't find out how to do that programmatically via C#. I have gone that far as to remove the properties from each mail containing that kind of property, like this:
IEnumerable<MailItem> listOfAssignedEmails = itemsToProcess.Where(
t => t.ItemProperties[MailExpiration.ExpirationDatePropertyName] != null);
foreach (MailItem email in listOfAssignedEmails)
{
// Note: The Delete() operation is deprecated. A more up-to-date method must be found.
email.ItemProperties[MailExpiration.ExpirationDatePropertyName].Delete();
email.Save();
}
... and yes, I know that the Delete() operation is deprecated; however, I couldn't find another method for removing the ItemProperty from the email (any suggestions are welcome).
Basically, the deletion of this Property is only going to be done very rarely (t. ex. if the user chooses to uninstall the Add-in. However, if there's any way to remove that property automatically, I would be happy to know.
Any suggestions will be greatly appreciated.
It is really a bad idea to remove a custom property from all emails that already have it: there is really no point since the user will never see them, but you will have to retouch (and thus change the last modified date) of a large number of emails.
Also note that named properties in MAPI are a finite resource - you can have at most 64k of them in a mailbox. Once a particular property mapping is used, you can never unmap it, even if there are no items that use that property.
Thirdly, doing anything Outlook related from an installer (rather than a VSTO addin) is a really bad idea - Windows installer runs in a service.
If you want to make sure the user no longer sees your custom fields as available properties in a view, you need to deal with the folder fields - they ar stored in a blob in a hidden (associated) message in that folder. OOM does not expose folder fields at all (if you don't count the AddToFolderFields parameter when calling UserProperties.Add). If using Redemption is an option (I am its author), it exposed RDOFolderFields object (accessible from RDOFolder2.FolderFields property) that allows to add or delete folder fields.
The list of properties shown on the screenshot belongs to the Folder.UserDefinedProperties property which returns a UserDefinedProperties object that represents the user-defined custom properties for the Folder object.
Use the ItemProperties.Remove method removes an object from the collection (from an item).
Use the ItemProperties property to return the ItemProperties collection. Use ItemProperties.Item(index), where index is the name of the object or the numeric position of the item within the collection, to return a single ItemProperty object.
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.
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.
the application is very large so giving a brief back ground and the problem
when the user logs in, a button is displayed having the text of the function he is allowed to call.
the function he is allowed is mapped in the database table
its made sure that the name of the actual function is same to the ones used in the db.
problem
the name is extracted, and stored as text field of button and also in a string variable.
now how am i supposed to call this function using the string variable which has the name stored in it!
like we type
name-of-function();
but here i dont know the name, the string at run time does so i cant write like
string()!!?
You will need to use reflection to do this. Here is a rough sketch of what you need to do:
// Get the Type on which your method resides:
Type t = typeof(SomeType);
// Get the method
MethodInfo m = t.GetMethod("methodNameFromDb");
// Invoke dynamically
m.Invoke(instance, null);
Depending on your actual needs you will have to modify this a little - lookup the used methods and types on MSDN: MethodInfo, Invoke
Well, no matter what you do, there is going to have to be some kind of mapping done between a database "function" and your "real" function. You can probably use Reflection using your Types and MethodInfo.
However, this sounds like a maintenance nightmare. It also sounds like you are reinventing user roles or the like. I would be very cautious about going down this path - I think it will be much more complex and problematic than you think.
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