This is not so much a question as to how to do something, but rather how I can implement something better or think about the problem differently.
I have a winforms application that allows the user to select multiple rows in a grid. These rows represent accounts and when the user selects the accounts and hits a button, a boolean property on the objects will change to whatever the selected value is regardless of it's existing state. However, if a validation method fails, a message is sent to the user and the boolean property needs to be set back to it's original state.
public void ModifyAccounts(List<DemoAccount> accts, bool updateIsSpecial)
{
// Dictionary that will hold the account ID along with the booleans original state
Dictionary<int, bool> originalState = new Dictionary<int, bool>();
foreach(var acct in accts)
{
// Add the current state to the dictionary
originalState.Add(acct.Id, acct.IsSpecial);
acct.IsSpecial = updateIsSpecial;
}
// Send the list to another method that loops through each account and checks
// for specific validation rules. Returns a collection of tuples. The tuple
// contains the account for item1 and a bool validated flag for item2
var valAccounts = ValidateAccounts(accts);
var failedAccounts = from obj in valAccounts
where !acct.Item2
select new
{
account = obj.Item1,
isValid = obj.Item2
};
if (failedAccounts.Count() > 0)
{
// Alert the user with custom msg box method that the accounts failed
// Do Custom Method
// Reset the values of the failed accounts to their previous state.
// It is possible that some accounts passed validation and were saved,
// only the failed accounts should be reset.
foreach (var obj in failedAccounts)
{
bool originalFlagState = false;
originalFlagStates.TryGetValue(obj.account.Id, out originalFlagState);
var origAccount = accts.Where(x => x.Id == obj.account.Id).FirstOrDefault();
origAccount.IsSpecial = originalFlagState;
}
}
}
I hope this isn't too confusing. I only have ~3 years of dev experience which is not a lot. However, I feel it's enough to understand when working on something that if it feels like there is a better way then I am probably not doing it correctly or efficiently. Modifying the account flag changes the object in the accounts list. Obviously adding the object to a new list will just create a reference to that object. So I can't do something like holding 2 collections one for modification and the other for original state. I also can't do a deep copy because the account class is not marked serializable. I cannot change this because of the type of object.
Thanks to anyone who can provide some advice or insight!
I do not understand why you want to validate after changing, and not beforehand.
But if you really have to validate and use undo afterwards there is a design pattern which supports this behavior
Have a look at the command pattern. Here is a code project link that describes how to implement it
http://www.codeproject.com/Articles/8303/Using-the-Command-pattern-for-undo-functionality
In your particular case I would iterate through the command stack and undo all commands which are used on failed accounts
It could look something like this
foreach (var obj in failedAccounts)
foreach ICommand command in commandStack
If(command.element.Equals(obj))
command.undo;
command.element should contain the element you want to change with your command.
if you dont want two foreach u could use System.Linq operations
Related
Having problem using update User with the google Admin SDK for C#.
https://developers.google.com/admin-sdk/directory/reference/rest/v1/users/update
This method supports patch semantics, meaning you only need to include the fields you wish to update. Fields that are not present in the request will be preserved, and fields set to null will be cleared.
This differs from the Patch as patch won't clear fields that are null but only update fields that have a value.
Problem is that I have to pass a full Google.Apis.Admin.Directory.directory_v1.Data.User class to the function which will contain null of even properties i do not want to clear.
example:
public User UpdateUser(Google.Apis.Admin.Directory.directory_v1.Data.User gUser)
{
UsersResource.UpdateRequest userUpdateRequest = _service.Users.Update(gUser, gUser.Id);
User updatedUser = userUpdateRequest.Execute();
return updatedUser;
}
Is there any way of modifying the Body in UpdateRequest before executing it?
Edit:
The UpdateRequest has a ModifyRequest Property that looks like this
I just have no Idea how to use it, any ideas?
public Action<HttpRequestMessage> ModifyRequest { get; set; }
As far as updating things to the concept of Null that is not something that can be done with PATCH. I recommend setting it to an empty string.
You should also not be sending the full user object if thats what you are currently doing. I am going to assume that you have done a users.list to find the user you want to update and change something in that user, say the name. Then you have simply submited the full user object to your method
UpdateUser(Google.Apis.Admin.Directory.directory_v1.Data.User gUser)
This wont work as some of the fields you have sent as part of the update/patch are not actually writeable.
What you should do instead would be to create a new user object change what ever it is you want
public User MakeUserAdmin(Google.Apis.Admin.Directory.directory_v1.Data.User gUserId)
{
var updateFields= new Google.Apis.Admin.Directory.directory_v1.Data.User();
change.IsAdmin = true;
change.Addresses = ""; // will set it to empty yes not null but the best you can do with this api.
UsersResource.UpdateRequest userUpdateRequest = _service.Users.Update(updateFields, gUserId);
User updatedUser = userUpdateRequest.Execute();
return updatedUser;
}
Notice how you just need to create a new object and update only the fields you need then send that.
Dont try to update every field, just update the ones that you know have changed. Dont include the id in the object that is not writeable either.
I am working with LDAP in my Windows Forms C# project.
I created a CheckListBox, and started to create a method that queries the Active Directory for all my computers is the environment.
The method is:
public string ComputerList()
{
DirectoryEntry rootDSE = new DirectoryEntry("LDAP://MyDomain.Local");
DirectorySearcher computerSercher = new DirectorySearcher(rootDSE);
computerSercher.PageSize = 10000;
computerSercher.Filter = "(&(objectClass=computer))";
}
I am also have as I said, a CheckListBox.
What I want to do is to have a result for the query and every computer that founds. add it to the Items property for the CheckListBox.
But I don't how even approach the result. it's not like PowerShell that gives you a list of objects...
Thank you
You're almost there. A few things:
Set the page size to 1000. AD won't give you any more than 1000 at a time, so if you set it to anything over that you'll only get 1000 (if DirectorySearcher doesn't get back what it considers a full page, it'll stop asking)
Add the attributes you want to read to the PropertiesToLoad collection. If you don't add anything, it'll give you every attribute with a value, which is a bunch of unnecessary data you won't use. You'll likely only want to see the cn attribute (Common Name).
Use FindAll() to get the results. Make sure you wrap this in a using statement to prevent memory leaks (the documentation says so).
When you look at the results, every property is presented as an array, whether it is or not in AD. So you'll need to use [0] in most cases. For future reference (not applicable here): if a property is not set in AD, it won't be in the Properties collection at all, so, for optional attributes, you'll have to use Properties.Contains() to see if it's there first.
Working from what you have, here is a method that will return a list of computer names:
public IEnumerable<string> ComputerList()
{
DirectoryEntry rootDSE = new DirectoryEntry("LDAP://MyDomain.Local");
DirectorySearcher computerSercher = new DirectorySearcher(rootDSE)
{
PageSize = 1000,
Filter = "(&(objectClass=computer))"
};
computerSercher.PropertiesToLoad.Add("cn");
using (var results = computerSercher.FindAll())
{
foreach (SearchResult result in results)
{
yield return (string) result.Properties["cn"][0];
}
}
}
Update: To answer your questions in your comment:
The yield basically tells it to "add this item to the collection that will be returned". There is a little more going on in the background, which you can read about here. But in simplest terms, it saves you from having to create your own list, add items to that list and return the list.
I changed the return type from string to IEnumerable<string> because you are getting multiple results from your search, so I assume you want to return all of those results. This method will give you a list of computer names, not just one computer name.
FindAll() returns a SearchResultCollection. For some reason I don't know, the objects returned from SearchResultCollection in a foreach are presented as object. So you need to cast them to SearchResult explicitly to use them.
working with Microsoft Bot Framework I'm setting states and data for conversation and user management.
I used
var state = message.GetBotPerUserInConversationData<ConversationState>("State");
if( state == null)
{
message.SetBotPerUserInConversationData("State", new ConversationState());
}
and
var data = context.PerUserInConversationData;
ConversationState state;
var ret = data.TryGetValue("State", out state);
to get my state.
Said that I should know properties, states I created calling Count property I get more then key/value pairs I created.
How to get the full list? It seems there is no way and may be object already inside whose name is unknown has info I need making useless my custom states.
Thanks
When you call context.PerUserInConversationData, you get the object that implements IBotDataBag (typically an instance of JObjectBotData class), and there is no way to programmatically access fields inside it.
If you want to understand which fields are inserted into this DataBag originally, you can have a look at the Bot Framework Source Code, or build you own copy of the framework which allows you to access keys in the JObjectBotData.
If you want to track your the fields that you put inside the bag in your code, you can create a wrapper which tracks those fields explicitly and stores their list in the DataBag.
Stripe Transfer JSON
I'm trying to get all charge IDs associated with a transfer.
var json = new StreamReader(context.Request.InputStream).ReadToEnd();
var stripeEvent = StripeEventUtility.ParseEvent(json);
StripeTransfer stripeTransfer;
switch (stripeEvent.Type)
{
case "transfer.created":
stripeTransfer = Stripe.Mapper<StripeTransfer>.MapFromJson(stripeEvent.Data.Object.ToString());
var transferId = stripeTransfer.Id;
stripeTransfer = _stripeManager.GetTransfer(transferId);
foreach (var charge in stripeEvent.Data.Object["transactions"])
{
}
_stripeManager.ProcessTransfer(stripeTransfer);
break;
In visual studio's immediate window, stripeEvent.Data.Object["transactions"] shows the data I want so I know that the json is getting sucked in properly. Those transactions are a collection of charges, they match my .net StripeCharge object. I'm having trouble figuring out how to iterate through the transactions...all I really need is the ID for each. Would like to see "transactions" as a C# IEnumerable object.
(the json in question is linked at the top of this post) let me know if more info is needed.
I've found the specific item is under ["transactions"]["data"][0]["id"] but there may be more than one so, still working on how to get them out and cast them...think I'm close but it seems like there should be a more elegant way of doing it.
EDIT,
Thanks Andrew, so even though I have all of the charge data, it is incoming data. So what I'll be doing is using the event to just get the id and then make the call to get the charge object from my own end to prevent any event spoofs. So that means I don't have to worry about casting at this point. Here is my solution, feel free to advise if there is a better way to do it
for (int i = 0; i < Int32.Parse(stripeEvent.Data.Object["transactions"]["total_count"].ToString()); i++)
{
string chargeId = stripeEvent.Data.Object["transactions"]["data"][i]["id"].ToString();
// do stuff with it
}
just for completeness:
Data under transactions looks like an array so should be able to index into them..
If you need to access to any other fields in the future you could construct c# objects but given the webhook 3rd party dance you are already doing probably not worth it as you only need id.
I want a method to update certain entries of an IEnumerable. I found that doing a foreach over the entries and updating the values failed as in the background I was cloning the collection. This was because my IEnumerable was backed by some LINQ->SQL queries.
By changing the method to take a List I have changed this behavior, Lists are always mutable and hence the method changes the actual objects in the list. Rather than demand a List is passed is there a Mutable interface I can use?
// Will not behave as consistently for all IEnumerables
public void UpdateYesterday (IEnumerable<Job> jobs) {
foreach (var job in jobs.Where(x => x.date == Yesterday)) {
job.done = true;
}
}
...
public class Job {
...
public DateTime Date { get; set; }
}
You're not changing the list at all here - the collection itself could be immutable and this code would still "work". You're changing the data within the items in the collection.
Imagine a row of houses - that's pretty immutable (creating or destroying a house is tricky) but you can still change the contents of those houses.
So, what you really need to know is whether the elements of the collection are going to be cloned or not... whether you'll get a collection of "new" jobs each time you perform the query, or whether it'll use the existing objects.
Here's one hypothetical way this might happen. Say you have a method that takes an existing data source and creates Job objects from that source.
Something like this:
public IEnumerable<Job> GetJobs() {
var rows = GetRowsFromDatabaseTable();
foreach (var row in rows)
yield return new Job(row.Name, row.Date, row.Etc);
}
Then if you had code that did this:
var jobs = GetJobs();
UpdateYesterday(jobs);
foreach (var job in jobs)
Console.WriteLine(job);
You would find that the jobs you printed using Console.WriteLine did not reflect the updates you performed in UpdateYesterday. This is because UpdateYesterday would have enumerated over the new objects created by GetJobs, and then your foreach loop would have enumerated over a new set of new objects created (again) by GetJobs.
On the other hand, if you simply changed that first line to this:
var jobs = GetJobs().ToList();
Then you would have put all those new objects created by GetJobs into a list, where they would persist, and thus your UpdateYesterday and foreach loop would be referring to the same objects (the ones in the list you created).
Does that make sense? I think this could very well be the problem you're encountering (in which case, the answer is indeed to construct a collection such as a List<Job> in memory from which you can access members to manipulate).
In answer to your question about being able to tell if an IEnumerable is mutable or not, though... well, I really don't think that is possible.
I've removed the old answer, as the new one seems to be what the OP needed.