Unit Of Work not work properly in aspnetboilerplate app-service - entity-framework

Work on aspnetboilerplate, have following kind of code in app-service, Unit Of Work not properly worked after delete if error raise, without executing the unitOfWork.Complete() data already deleted from the database.
using (var unitOfWork = _unitOfWorkManager.Begin())
{
//delete all items in db....
var response = _grouppermissionRepository.HardDelete(p => p.GroupId == groupId);
foreach (var item in pageGroupPermissions)
{
if (item.IsChecked == true)
{
var grouppermissionObj = new Entities.Setup.GroupPermission()
{
CompanyId = null,
GroupId = item.GroupId,
IsActive = true,
IsDefault = true,
IsDeleted = false,
PageId = item.PageId,
Permission = item.Permission,
TenantId = 2
};
groupPermissions.Add(grouppermissionObj);
}
}
_grouppermissionRepository.GetDbContext().AddRange(groupPermissions);
unitOfWork.Complete();
}

Related

Error VS403357 when batch creating many work items in Azure DevOps using .NET API

I'm trying to use the Azure DevOps .NET API to batch create WorkItems in a AzureDevOps repository, but when I submit the batch request, I'm getting back an error message: "VS403357: Work items in the batch are expected to be unique, but found work item with ID -1 in more than one request."
Here's my code:
public void ExecuteWorkItemMigration(int[] workItemIds, IProgress<ProgressResult> progress = null)
{
var wiql = "SELECT * FROM WorkItems";
var query = new Query(_workItemStore, wiql, workItemIds);
var workItemCollection = query.RunQuery();
string projectName = MainSettings.AzureDevOpsSettings.ProjectName;
List<WitBatchRequest> batchRequests = new List<WitBatchRequest>();
foreach (WorkItemTfs tfsWorkItem in workItemCollection)
{
JsonPatchDocument document = CreateJsonPatchDocument(tfsWorkItem);
string workItemType = GetWorkItemType(tfsWorkItem);
WitBatchRequest wibr = _azureDevopsWorkItemTrackingClient.CreateWorkItemBatchRequest(projectName, workItemType,
document, true, true);
batchRequests.Add(wibr);
}
List<WitBatchResponse> results = _azureDevopsWorkItemTrackingClient.ExecuteBatchRequest(batchRequests).Result;
}
private static JsonPatchDocument CreateJsonPatchDocument(WorkItemTfs tfsWorkItem, int id = -1)
{
var document = new JsonPatchDocument();
document.Add(
new JsonPatchOperation
{
Path = "/id",
Operation = Operation.Add,
Value = id
});
document.Add(
new JsonPatchOperation
{
Path = "/fields/System.Title",
Operation = Operation.Add,
Value = tfsWorkItem.Title
});
if (tfsWorkItem.Fields.Contains("ReproSteps"))
document.Add(
new JsonPatchOperation
{
Path = "/fields/Microsoft.VSTS.TCM.ReproSteps",
Operation = Operation.Add,
Value = tfsWorkItem.Fields["ReproSteps"].Value
});
}
Any suggestions about what I need to do to get this working properly?
I have tried submitting different unique ID's but it doesn't seem to prevent the error from happening.
You need to use unique negative ID's for creating the WorkItem ID.
Something like this:
public void ExecuteWorkItemMigration(int[] workItemIds, IProgress<ProgressResult> progress = null)
{
var wiql = "SELECT * FROM WorkItems";
var query = new Query(_workItemStore, wiql, workItemIds);
var workItemCollection = query.RunQuery();
string projectName = MainSettings.AzureDevOpsSettings.ProjectName;
List<WitBatchRequest> batchRequests = new List<WitBatchRequest>();
int id = -1;
foreach (WorkItemTfs tfsWorkItem in workItemCollection)
{
JsonPatchDocument document = CreateJsonPatchDocument(tfsWorkItem, id--);
string workItemType = GetWorkItemType(tfsWorkItem);
WitBatchRequest wibr = _azureDevopsWorkItemTrackingClient.CreateWorkItemBatchRequest(projectName, workItemType,
document, true, true);
batchRequests.Add(wibr);
}
List<WitBatchResponse> results = _azureDevopsWorkItemTrackingClient.ExecuteBatchRequest(batchRequests).Result;
}

ConfirmEmailAsync() method is not working

I am having issue in confirming new user email. the Confirm email link works for first 20 minutes , but after 50 minutes the link expires. I have set the token expiration time to 24 hours. Please help me in resolving this issue. I am stuck on it for last 2 days:(.My code is as follows:
I am setting the token lifetime in Create() method in ApplicationUserManager as following:
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = _settings.ConfirmationAndResetTokenExpirationTimeSpan
};
}
And then In AccountsController, the Create method for new user is geiven below. The SendEmailAsync method consist of email subject, email body, generated password and the callback uri.
[Authorize(Roles = Roles.Bam.Name.Admin)]
[HttpPost]
[Route(Routes.Accounts.Template.Create, Name = Routes.Accounts.Name.Create)]
public async Task<IHttpActionResult> Create(CreateUserBindingModel createUserBindingModel)
{
IHttpActionResult result;
var memberNameExists = UserManager.Users.Any(x => x.MemberName.ToLower() == createUserBindingModel.MemberName.ToLower());
if (!memberNameExists)
{
var applicationUser = new ApplicationUser
{
UserName = createUserBindingModel.Email,
Email = createUserBindingModel.Email,
FirstName = createUserBindingModel.FirstName,
LastName = createUserBindingModel.LastName,
Company = createUserBindingModel.Company,
Location = createUserBindingModel.Location,
PhoneNumber = createUserBindingModel.PhoneNumber,
MemberName = createUserBindingModel.MemberName,
LastLoginDate = SqlDateTime.MinValue.Value,
CreateDate = DateTime.Now,
CreatedBy = User.Identity.GetUserId(),
UpdateDate = DateTime.Now,
UpdatedBy = User.Identity.GetUserId(),
TwoFactorEnabled = createUserBindingModel.TwoFactorEnabled,
SecurityResetRequired = true,
PasswordExpirationDate = DateTime.Now.AddDays(Convert.ToDouble(ConfigurationManager.AppSettings["PasswordExpirationDays"]))
};
if (!string.IsNullOrEmpty(createUserBindingModel.AvatarBase64))
{
var avatarBytes = Convert.FromBase64String(createUserBindingModel.AvatarBase64);
var resizedAvatarBytes = ImageResizer.ResizeImage(avatarBytes, _avatarWidth, _avatarHeight);
applicationUser.UserAvatar = new ApplicationUserAvatar
{
Avatar = resizedAvatarBytes
};
}
var generatedPassword = PasswordGenerator.GenerateStrongPassword(10, 10);
var identityResult = await UserManager.CreateAsync(applicationUser, generatedPassword);
if (identityResult.Succeeded)
{
await UserManager.AddToRolesAsync(applicationUser.Id, createUserBindingModel.Roles.ToArray());
var token = await UserManager.GenerateEmailConfirmationTokenAsync(applicationUser.Id);
var callbackUri = string.Format("{0}?userId={1}&token={2}", createUserBindingModel.EmailConfirmationCallbackUri, applicationUser.Id, HttpUtility.UrlEncode(token));
await UserManager.SendEmailAsync(applicationUser.Id, Email.Confirmation.Subject, string.Format(Email.Confirmation.Body, string.Format("{0} {1}", applicationUser.FirstName, applicationUser.LastName), callbackUri, generatedPassword, _settings.AccessTokenExpirationTimeSpan.TotalHours));
var userUrl = new Uri(Url.Link(Routes.Accounts.Name.Get, new { id = applicationUser.Id }));
var roles = await UserManager.GetRolesAsync(applicationUser.Id);
var contract = _accountsMapper.ToContract(applicationUser, roles);
result = Created(userUrl, contract);
}
else
{
result = GetErrorResult(identityResult);
}
}
else
{
ModelState.AddModelError(string.Empty, "Member Name already exists!");
result = BadRequest(ModelState);
}
return result;
}
Once the email is generated the UI has following JS angular code which gets executed and the provide the userid and token to service.
Angular JS code:
angular.module('confirmEmailModule').factory('confirmEmailFactory', function ($http) {
var factory = {};
factory.confirmEmail = function(userId, token) {
var encodedToken = encodeURIComponent(token);
var uri = '/identity/api/accounts/confirmemail?userId=' + userId + '&token=' + token;
return $http.post(uri);
}
return factory;
});
and the Service is :
[AllowAnonymous]
[HttpPost]
[Route(Routes.Accounts.Template.ConfirmEmail, Name = Routes.Accounts.Name.ConfirmEmail)]
public async Task<IHttpActionResult> ConfirmEmail([FromUri] string userId, [FromUri] string token)
{
//var decodedToken = HttpUtility.UrlDecode(token);
var identityResult = await UserManager.ConfirmEmailAsync(userId, token);
var result = identityResult.Succeeded ? StatusCode(HttpStatusCode.NoContent) : GetErrorResult(identityResult);
return result;
}
Please advice.
I found the solution to this issue. I am posting it if somebody faced the same issue. In my case the services and web API were on different servers. Different machine keys caused this issue. So I generated the machine key for my Web application and posted the same machine key in web.config file of Identity service. After that it worked. For more information on generating machine key, following link is helpful.
http://gunaatita.com/Blog/How-to-Generate-Machine-Key-using-IIS/1058
This is what worked for me. Hope it helps out;
public async Task<IActionResult> ConfirmEmail(string userId, string token)
{
if (userId == null || token == null)
{
return RedirectToAction("employees", "home");
}
var user = await userManager.FindByIdAsync(userId);
if (user == null)
{
ViewBag.ErrorMessage = $"The User ID {userId} is invalid";
return View("NotFound");
}
var result = await userManager.ConfirmEmailAsync(user, Uri.EscapeDataString(token));
if (result != null)
{
user.EmailConfirmed = true;
await userManager.UpdateAsync(user);
return View();
}
}

Handling concurrency exceptions when passing the objects ids and timestamps using jQuery

I have the following business scenario inside my Asp.net MVC 4 asset management system :-
Scenario 1) A user selects multiple servers , then he selects a Rack Tag ,and click on
assign . so the selected servers will be assigned to the new Rack.
Scenario 2) And i want to check for any concurrency exception , if for example the selected
servers have been modified by another user since they were retrieved .
so i have wrote the following jQuery which will send the object ids+timestamps to the action method:-
$('body').on("click", "#transferSelectedAssets", function () {
var boxData = [];
$("input[name='CheckBoxSelection']:checked").each(function () {
boxData.push($(this).val());
});
var URL = "#Url.Content("~/Server/TransferSelectedServers")";
$.ajax({
type: "POST",
url: URL,
data: { ids: boxData.join(","), rackTo: $("#rackIDTo").val()}
,
success: function (data) {
addserver(data); })});
and inside the action method i have the following code:-
public ActionResult TransferSelectedServers(string ids, int? rackTo)
{
if (ModelState.IsValid)
{
try
{
var serverIDs = ids.Split(',');
int i = 0;
foreach (var serverinfo in serverIDs)
{
var split = serverinfo.Split('~');
var name = split[0];
//System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] bytearray = Encoding.Default.GetBytes(split[1]);
i++;
var server = repository.FindServer_JTechnology(Int32.Parse(name));
if (server == null)
return Json(new { IsSuccess = false, reload = true, description = " Some Servers might have been deleted, Transferre process has been cancelled .", rackid = rackFrom }, JsonRequestBehavior.AllowGet);
server.RackID = rackTo;
server.timestamp = bytearray;
string ADusername = User.Identity.Name.Substring(User.Identity.Name.IndexOf("\\") + 1);
repository.InsertOrUpdateServer(server, ADusername, server.Technology.IT360ID.Value, server.IT360SiteID, new bool(), server.Technology);
}
repository.Save();
return Json(new { IsSuccess = true, description = i + " Server/s Transferred Successfully To Rack " + }, JsonRequestBehavior.AllowGet);
}
catch (DbUpdateConcurrencyException e)
{
return Json(new { IsSuccess = false, reload = true, description = "records has been modified by antoehr user" }, JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
return Json(new { IsSuccess = false, reload = true, description = " Server/s Can not Be Transferred to the Selected Rack " }, JsonRequestBehavior.AllowGet);
}
}
return RedirectToAction("Details", new { id = rackTo });
}
and the repository method looks as follow:-
public void InsertOrUpdateServer(TMSServer server, string username, long assetid, long? siteid = 0, bool isTDMHW = false, Technology t = null)
{
server.IT360SiteID = siteid.Value;
tms.Entry(server).State = EntityState.Modified;
var technology = tms.Technologies.Single(a => a.TechnologyID == server.TMSServerID);
technology.IsManaged = t.IsManaged;
tms.Entry(technology).State = EntityState.Modified;
InsertOrUpdateTechnologyAudit(auditinfo);
}
}
but currently if two users selects the same servers and assign them to tow different racks , no concurrency exception will be raised ?
Can anyone advice ? baring in mind that if two users edit single object then one of them will get an concurrent exception message. so my timestamp column is defined correctly.
Thanks

Referential integrity constraint violation. A Dependent Role has multiple principals with different values

I get the following error when I add more than one entity to a dbcontext in EF6.0, if i only add the first, it saves perfectly, if i add a second one then I get the error.
Error:
"Referential integrity constraint violation. A Dependent Role has multiple principals with different values."
Code
using (var context = new ListingLocatorContext())
{
var listing1 = new Listing
{
UserID = 1,
ListingDate = DateTime.Now,
ExpiryDate = DateTime.Now,
Address = string.Empty,
PostalCode = string.Empty,
IsApproved = true,
CityID = 71,
IsTop = true,
IsActive = true,
ViewCount = 0
};
listing1.ListingTypes.Add(new ListingType
{
TypeID = 4
});
var listing2 = new Listing
{
UserID = 1,
ListingDate = DateTime.Now,
ExpiryDate = DateTime.Now,
Address = string.Empty,
PostalCode = string.Empty,
IsApproved = true,
CityID = 71,
IsTop = true,
IsActive = true,
ViewCount = 0
};
listing2.ListingTypes.Add(new ListingType
{
TypeID = 5
});
context.Listings.Add(listing1);
context.Listings.Add(listing2);
context.SaveChanges();
}
DB Diagram
Try replacing those two statements:
listing1.ListingTypes.Add(new ListingType {
TypeID = 4
});
and
listing2.ListingTypes.Add(new ListingType {
TypeID = 5
});
with
var listingType1 = new ListingType {
TypeID = 4,
Listing = listing1
};
var listingType2 = new ListingType {
TypeID = 5,
Listing = listing2
};
context.ListingTypes.Add(listingType1);
context.ListingTypes.Add(listingType2);

Entity Framework - how to save entity without saving related objects

In my Entity Framework, I have three related entities 'Client', 'ClientAddress' and 'LookupAddressType'. "LookupAddressType" is a master class specifying the type of available address type, like business address, residential address etc. ClientAddress depend on LookupAddresstype and Client. While saving a Client entity with relevant ClientAddress data, i'm getting following error.
"Violation of PRIMARY KEY constraint 'PK_LookupAddressType'. Cannot
insert duplicate key in object 'dbo.LookupAddressType'. The statement
has been terminated.
I do not need LookupAddressType to be inserted. Here I just need the relevant lookupAddressTypeId to be inserted in clientAddress entity.
The Saving code is like this:
Add(Client);
_objectContext.SaveChanges();
how can i do this?
The Load Code is below:
private void LoadClientDetails(EFEntities.Client _Client)
{
EFEntities.LookupClientStatu clientStatus;
var clientAddressList = new List<ClientAddress>();
if (_Client == null)
{
return;
}
//Assign data to client object
_Client.ClientName = rtxtName.Text;
_Client.Alias = rtxtAlias.Text;
_Client.ClientCode =Int32.Parse(rtxtClientCode.Text);
_Client.TaxPayerID = rtxtTaxPayerId.Text;
if (rcboStatus.SelectedIndex != 0)
{
clientStatus = new EFEntities.LookupClientStatu
{
ClientStatusID = (Guid) (rcboStatus.SelectedValue),
ClientStatusDescription = rcboStatus.Text
};
_Client.LookupClientStatu = clientStatus;
}
//_Client.Modified = EnvironmentClass.ModifiedUserInstance.Id;
_Client.EffectiveDate = rdtEffectiveDate.Value;
if (rdtExpDate.Value != rdtExpDate.MinDate)
{
_Client.ExpirationDate = rdtExpDate.Value;
}
else
{
_Client.ExpirationDate = null;
}
_Client.StartDate = DateTime.Now;
EFEntities.ClientAddress clientAddress = null;
// Iesi.Collections.Generic.ISet<ClientAddress> clientAddress = new HashedSet<ClientAddress>();
foreach (var cAddress in _clientController.client.ClientAddresses)
{
clientAddress = cAddress;
break;
}
if (clientAddress == null)
{
clientAddress = new EFEntities.ClientAddress();
}
clientAddress.Address1 = rtxtClientAdd1.Text;
clientAddress.Address2 = rtxtClientAdd2.Text;
clientAddress.Address3 = rtxtClientAdd3.Text;
// Address type details
if (rcboClientAddType.SelectedIndex != -1)
{
clientAddress.LookupAddressType = new EFEntities.LookupAddressType
{
AddressTypeID = (Guid) (rcboClientAddType.SelectedValue),
AddressTypeDescription = rcboClientAddType.Text
};
//clientAddress.AddressType.Id = Convert.ToByte(rcboClientAddType.SelectedValue);
}
clientAddress.City = rtxtClientCity.Text;
clientAddress.Client = _Client;
\
_Client.ClientAddresses.Add(clientAddress);
}
Well I did this to the following lines of code to make it work.
if (rcboClientAddType.SelectedIndex != -1)
{
clientAddress.LookupAddressType = new EFEntities.LookupAddressType
{
AddressTypeID = (Guid) (rcboClientAddType.SelectedValue),
AddressTypeDescription = rcboClientAddType.Text
};
//clientAddress.AddressType.Id = Convert.ToByte(rcboClientAddType.SelectedValue);
}
I changed the above code into this
if (rcboClientAddType.SelectedIndex != -1)
{
//clientAddress.LookupAddressType = new EFEntities.LookupAddressType
// {
// AddressTypeID = (Guid) (rcboClientAddType.SelectedValue),
// AddressTypeDescription = rcboClientAddType.Text
// };
clientAddress.AddressTypeID = (Guid)(rcboClientAddType.SelectedValue);
}