When I try to save the events to the store I get the following exception:
The commit must be uniquely identified.\r\nParameter name: attempt
But my code always generates a new New Guid for the commit (as per NEventStore example)
public void Save(Guid aggregateId, IEnumerable<Event> events, int expectedVersion)
{
var eventList = events as IList<Event> ?? events.ToList();
using (var scope = new TransactionScope())
using (var stream = store.OpenStream(aggregateId, 0, int.MaxValue))
{
if(stream.StreamRevision != expectedVersion)
throw new ConcurrencyException();
foreach (var #event in eventList)
{
stream.Add(new EventMessage { Body = #event });
}
stream.CommitChanges(Guid.NewGuid());
scope.Complete();
}
foreach (var #event in eventList)
{
publisher.Publish(#event);
}
}
Does anyone have any idea why this is happening?
The message is misleading. It is thrown here when this check...
attempt.StreamId != Guid.Empty && attempt.CommitId != Guid.Empty
Is false. So it should say: both the CommitId and StreamId must not be empty.
Related
I have this Action method which act as an API end point inside our ASP.NET MVC-5, where it search for a username and return the username Phone number and Department from Active Directory (we are serializing the object using Newtonsoft.net):-
public ActionResult UsersInfo2()
{
DomainContext result = new DomainContext();
try
{
// create LDAP connection object
DirectoryEntry myLdapConnection = createDirectoryEntry();
string ADServerName = System.Web.Configuration.WebConfigurationManager.AppSettings["ADServerName"];
string ADusername = System.Web.Configuration.WebConfigurationManager.AppSettings["ADUserName"];
string ADpassword = System.Web.Configuration.WebConfigurationManager.AppSettings["ADPassword"];
using (var context = new DirectoryEntry("LDAP://mydomain.com:389/DC=mydomain,DC=com", ADusername, ADpassword))
using (var search = new DirectorySearcher(context))
{
// create search object which operates on LDAP connection object
// and set search object to only find the user specified
// DirectorySearcher search = new DirectorySearcher(myLdapConnection);
// search.PropertiesToLoad.Add("telephoneNumber");
search.Filter = "(&(objectClass=user)(sAMAccountName=test.test))";
SearchResult r = search.FindOne();
ResultPropertyCollection fields = r.Properties;
foreach (String ldapField in fields.PropertyNames)
{
// cycle through objects in each field e.g. group membership
// (for many fields there will only be one object such as name)
string temp;
// foreach (Object myCollection in fields[ldapField])
// {
// temp = String.Format("{0,-20} : {1}",
// ldapField, myCollection.ToString());
if (ldapField.ToLower() == "telephonenumber")
{
foreach (Object myCollection in fields[ldapField])
{
result.Telephone = myCollection.ToString();
}
}
else if (ldapField.ToLower() == "department")
{
foreach (Object myCollection in fields[ldapField])
{
result.Department = myCollection.ToString();
}
}
// }
}
string output = JsonConvert.SerializeObject(result);
return Json(output,JsonRequestBehavior.AllowGet);
}
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return View(result);
}
now the return JSON will be as follow:-
"\"DisplayName\":null,\"Telephone\":\"123123\",\"Department\":\"IT\",\"Name\":null,\"SamAccountName\":null,\"DistinguishedName\":null,\"UserPrincipalName\":null}"
but in our case we need to return a status code beside the return json data. for example inccase there is an exception we need to return an error code,also if we are able to get the user's info we need to pass succes code 200, and so on.. so how we can achieve this?
you can try something like this
var statusCode=200;
string output = JsonConvert.SerializeObject( new { result = result, StatusCode = statusCode);
but nobody usually do this. When users call API they can check status code that HTTP Client returns, using code like this
var response = await client.GetAsync(api);
//or
var response = await client.PutAsJsonAsync(api, data);
var statusCode = response.StatusCode.ToString();
//or usually
if (response.IsSuccessStatusCode) {...}
else {...}
I am new in ASP.NET MVC Web API. I am trying to modified the return JSon to this format
{
"Error": false,
"Status": 200,
"Response": []
}
Now I able to do that by follow this post https://www.devtrends.co.uk/blog/wrapping-asp.net-web-api-responses-for-consistency-and-to-provide-additional-information . But the problem is I not able to show ModelState error like 'First name is required' because the code only show the first hit error.
if (error != null)
{
content = null;
//only show the first error
errorMessage = error.Message;
}
So I did some modification, now the code is written as below:
if (error != null)
{
content = null;
foreach(var e in error)
{
//if the error's type is ModelState
if (e.Key.Equals("ModelState"))
{
var allErrors = e.Value;
foreach (var modelError in (IEnumerable<KeyValuePair<string, object>>)allErrors)
{
var msg = modelError;
errorMessage = string.Concat(errorMessage, ", ", ((String[]) modelError.Value)[0]);
}
}
else
{
errorMessage = e.Value.ToString();
}
}
}
Now it's able to show all errors but the code is messy. I am writing this questions to find out what is the proper way to write this kind of code.
You can iterate over all the errors and concatenate them using StringBuilder. String.Join is much faster than Append for less than 1000 items (it is unlikely you will have so many errors in the modelstate object):
public static ValidationResult CheckValid(ModelStateDictionary modelState, string httpName = null)
{
if (!modelState.IsValid)
{
var sb = new StringBuilder();
sb.AppendLine(httpName + " failed: Invalid Json:");
foreach (var pair in modelState)
{
var error = String.Join(";", pair.Value.Errors.Select
(
i =>
{
if (!String.IsNullOrEmpty(i.ErrorMessage))
return i.ErrorMessage;
return i.Exception.Message;
}
));
sb.AppendLine($"Property: {pair.Key} Errors: ({error})");
}
return new ValidationResult(false, sb.ToString());
}
else
return new ValidationResult(true, "");
}
I'm wondering how I could get a list of members of an AD group.
Checking if an entered password of a user is correct works perfectly fine. For this I'm using Novell's Ldap.NetStandard:
private bool IsUserValid(string userName,string userPassword)
{
try{
using (var connection = new LdapConnection { SecureSocketLayer = false })
{
connection.Connect("test.local", LdapConnection.DEFAULT_PORT);
connection.Bind(userDn, userPassword);
if (connection.Bound)
{
return true;
}
}
}
catch (LdapException ex)
{
Console.WriteLine(ex.Massage);
}
return false;
}
What I want now is something like this:
bool isUserInGroup("testUser","testGroup");
The problem is I can't get my method working:
public bool IsUserMemberOfGroup(string userName,string groupName)
{
var ldapConn = GetConnection();
var searchBase = "";
var filter = $"(&(objectClass=group)(cn={groupName}))";
var search = ldapConn.Search(searchBase, LdapConnection.SCOPE_BASE, filter, null, false);
while (search.hasMore())
{
var nextEntry = search.next();
if (nextEntry.DN == userName)
return true;
}
return false;
}
What ever I'm doing, I'm not getting back any value from my Ldap.Search()...
Now there is an implementation of System.DirectoryServices.AccountManagement for .NET Core 2. It is available via nuget.
With this package you are able to things like that:
using (var principalContext = new PrincipalContext(ContextType.Domain, "YOUR AD DOMAIN"))
{
var domainUsers = new List<string>();
var userPrinciple = new UserPrincipal(principalContext);
// Performe search for Domain users
using (var searchResult = new PrincipalSearcher(userPrinciple))
{
foreach (var domainUser in searchResult.FindAll())
{
if (domainUser.DisplayName != null)
{
domainUsers.Add(domainUser.DisplayName);
}
}
}
}
This performs a search for the user in your domain.Nearly the same is possible for searching your group. The way I used to search my AD (description in my question) is now obsolet:
Checking if an entered password of a user is correct works perfectly
fine. For this I'm using Novell's Ldap.NetStandard:
How about:
HttpContext.User.IsInRole("nameOfYourAdGroup");
(namespace System.Security.Claims)
I have been facing this problem with assigning users to a proper role. The code looks just fine, but in reality half of the users gets a proper role, the other half stays without a role at all. Here is the method which does it:
public IdentityResult RefreshUserGroupRoles(long? userId)
{
if (userId == null) throw new ArgumentNullException(nameof(userId));
var user = _userManager.FindById(userId.Value);
if(user == null)
{
throw new ArgumentNullException(nameof(userId));
}
// Remove user from previous roles:
var oldUserRoles = _userManager.GetRoles(userId.Value);
if (oldUserRoles.Count > 0)
{
_userManager.RemoveFromRoles(userId.Value, oldUserRoles.ToArray());
}
// Find the roles this user is entitled to from group membership:
var newGroupRoles = this.GetUserGroupRoles(userId.Value);
// Get the damn role names:
var allRoles = _roleManager.Roles.ToList();
var addTheseRoles = allRoles.Where(r => newGroupRoles.Any(gr => gr.AppRoleId == r.Id));
var roleNames = addTheseRoles.Select(n => n.Name).ToArray();
//_db.Database.CurrentTransaction.Commit();
// Add the user to the proper roles
var transaction = _db.Database.BeginTransaction();
IdentityResult result;
try
{
result = _userManager.AddToRoles(userId.Value, roleNames);
transaction.Commit();
_db.DbContextTransactionAu.Commit(); //This is for Audit
}
catch (Exception)
{
transaction.Rollback();
throw;
}
_db.DbContextTransactionAuDispose?.Dispose();
return result;
}
public IEnumerable<AppGroupRole> GetUserGroupRoles(long userId)
{
var userGroups = this.GetUserGroups(userId).ToList();
if (userGroups.Count == 0) return new Collection<AppGroupRole>().AsEnumerable();
var userGroupRoles = new List<AppGroupRole>();
foreach(var group in userGroups)
{
userGroupRoles.AddRange(group.AppRoles.ToArray());
}
return userGroupRoles;
}
Any idea what could be wrong?
I have an if statement in my Controller which decides whether a checkbox is checked or not.
It works fine in the if statement and changes the properties, but when i go to send it back to the view these changes aren't saved.
Controller
public ActionResult GetUserRights(string userLogin)
{
if (userLogin != null)
{
Manager manager = new Manager();
var userlogin = manager.GetUserData(userLogin);
var userrights = userlogin.RightsId.Select(s => new { id = s, text = s });
var rightdetails = manager.GetAllRightsRows();
var rightsDetails = from r in rightdetails
orderby r.Id
select new RightDetail
{
RightID = r.Id,
RightDescription = r.Description,
RightName = r.Name,
ParentID = r.ParentId,
TypeColor = r.TypeColor,
Value = r.Value,
Checked = false
};
foreach (var userright in userrights)
{
foreach (var rightdets in rightsDetails)
{
if(rightdets.RightID == userright.id)
{
rightdets.Checked = true;
break;
}
}
}
return View("_RightsTreeListPartial", rightsDetails); <==== ALL CHECKED
PROPERTIES ARE false EVEN THOUGH SOME ARE BEING CHANGED IN THE IF STATEMENT.
}
return View("Index");
}
Let me know if you need any more info.
Thanks
With an IEnumerable, I am not sure of the reason why, but you cannot edit an item using an if statement so the code below is correct and does what it is supposed to, however as it is IEnumerable non of the changes are saved, also the process below is very heavy and long winded for what we need to do.
Original Code
foreach (var userright in userrights)
{
foreach (var rightdets in rightsDetails)
{
if(rightdets.RightID == userright.id)
{
rightdets.Checked = true;
break;
}
}
}
The new code takes a lot less time and will therefore improve the wait time. Firstly the IEnumerable is converted to a List, then, using a for-loop, the data is iterated through until a match is found, then within an if statement the item is changed (using original code and just converting from IEnumerable to List should work but I wouldn't recommend using it).
New Code
var rightdetail = rightsDetails.ToList();
foreach (var userright in userrights)
{
for (var i = 0; i < rightdetail.Count(); i++)
{
if (rightdetail[i].RightID == userright.id)
{
rightdetail[i].Checked = true;
break;
}
}
}