I created a static class that I want to use in various projects. I am trying to make this as independent as I can but it's not updating and I'm getting no error messages. I am using .Net Framework 4.0 client.
Here is the code:
using System;
using System.Linq;
namespace SSS.ServicesConfig.data
{
public partial class GlobalSetting
{
public static GlobalSetting GetGlobalSetting()
{
try
{
using (var context = new SuburbanEntities())
{
return (from gs in context.GlobalSettings
select gs).FirstOrDefault();
}
}
catch (Exception ex)
{
Logging.Log("An error occurred.", "GetGlobalSetting", Apps.ServicesConfig, ex);
throw new Exception(string.Format("Unable to retrieve data: [{0}].", ex.Message));
}
}
public static void SaveGlobalSettings(GlobalSetting globalSetting)
{
using (var context = new SuburbanEntities())
{
context.Attach(globalSetting);
context.SaveChanges();
}
}
}
}
Is the attach not done the right way? If not, how should I be saving it when it comes back in?
You have to set the state to modified:
context.Attach(globalSetting);
context.Entry(globalSetting).State = EntityState.Modified;
context.SaveChanges();
If i understand you correctly, I suggest you try removing the using statement in both methods and declare the context in this manner or better still a private varialbe to hold the local context variable.
var context = new SuburbanEntities())
context.Attach(globalSetting);
context.SaveChanges();
I understand you're in the ObjectContext API, so the way to mark an entity as changed is:
context.ObjectStateManager
.ChangeObjectState(globalSetting, EntityState.Modified);
after you attached the object to the context.
must mark it modified, try
context.Attach(globalSetting);
var gs = context.Entry(globalSetting);
gs.State = EntityState.Modified;
context.SaveChanges();
Related
I have created service which communicates with my database. GetAvailableUserId service's method cannot be run simultaneously, because I don't want to return same user's id for two different calls. So far I have managed this:
public class UserService : IUserService
{
public int GetAvailableUserId()
{
using (var context = new UsersEntities())
{
using (var transaction = context.Database.BeginTransaction())
{
var availableUser = context.User
.Where(x => x.Available)
.FirstOrDefault();
if (availableUser == null)
{
throw new Exception("No available users.");
}
availableUser.Available = false;
context.SaveChanges();
transaction.Commit();
return availableUser.Id;
}
}
}
}
I wanted to test if service will work as intended, so I created simple console application to simulate synchronous requests:
Parallel.For(1, 100, (i, state) => {
var service = new UserServiceReference.UserServiceClient();
var id = service.GetAvailableUserId();
});
Unfortunately, It failed that simple test. I can see, that it returned same id for different for iterations.
Whats wrong there?
If I understood you correctly, you wan to lock method from other threads. If yesm then use lock:
static object lockObject = new object();
public class UserService : IUserService
{
public int GetAvailableUserId()
{
lock(lockObject )
{
// your code is omitted for the brevity
}
}
}
You need to spend some time and delve into the intricadies of SQL Server and EntityFramework.
Basically:
You need a database connection that handles repeatable results (which is a database connection string setting).
You need to wrap the interactions in EntityFramework within one transaction so that multiple instances do not possibly return the same result in the query and then make problems in the save.
Alternative method to achieve this is to catch DbUpdateConcurrencyException to check whether values in the row have changed since retrieving when you try to save.
So if e.g. the same record is retrieved twice. The first one to have the Available value updated in the database will cause the other one to thow concurrency exception when it tries to save because the value has changed since it was retrieved.
Microsoft - handling Concurrency Conflicts.
Add ConcurrencyCheck attribute above the Available property in your entity.
[ConcurrencyCheck]
public bool Available{ get; set; }
Then:
public int GetAvailableUserId()
{
using (var context = new UsersEntities())
{
try
{
var availableUser = context.User
.Where(x => x.Available)
.FirstOrDefault();
if (availableUser == null)
{
throw new Exception("No available users.");
}
availableUser.Available = false;
context.SaveChanges();
return availableUser.Id;
}
catch (DbUpdateConcurrencyException)
{
//If same row was already retrieved and updated to false, do not save, instead call the method again to get the next true row.
return GetAvailableUserId();
}
}
}
What is a good way to bubble up a DbUpdateConcurrencyException to the view from the grain?
I'm currently working on an Orlean's prototype that has a custom state that I'm using Entity Framework Core to communicate with the DB and using the optimistic concurrency patterns built into EF Core to manage the concurrency issues.
Where I'm having an issue is that I want to bubble up my Exception from the grain to the view and am not receiving it on the view end.
I'm trying to accomplish this because I want to deal with some of the concurrency issues that are more pressing on the view so that the user can decide or at least be alerted to the issue.
I brought this up on the Orlean's Gitter, but didn't get many ideas from it.
Example of my code for updating:
public Task UpdateUser(User user)
{
//Reason for second try/catch is to bubble the error to controller
try
{
userState = new User
{
Username = this.GetPrimaryKeyString(),
accountType = user.accountType,
FName = user.FName,
LName = user.LName,
RowVersion = user.RowVersion,
CreatedDate = user.CreatedDate
};
UpdateState();
}
catch (DbUpdateConcurrencyException ex)
{
throw ex;
}
return Task.CompletedTask;
}
public Task UpdateState()
{
using (var context = new OrleansContext())
{
context.users.Update(userState);
try
{
context.SaveChanges();
}
catch ( DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var clientValues = (User)entry.Entity;
var databaseEntry = entry.GetDatabaseValues();
//Make sure the row wasn't deleted
if(databaseEntry != null)
{
var databaseValues = (User)databaseEntry.ToObject();
if(clientValues.accountType != databaseValues.accountType)
{
//Bubble up the exception to controller for proper handling
throw ex;
}
//Update Row Version to allow update
userState.RowVersion = databaseValues.RowVersion;
context.SaveChanges();
}
}
}
return Task.CompletedTask;
}
I'm open to any suggestions on this as long as it allows the user to be alerted to the Exception and can view their data and the current DB values.
There is a chance that the exception is not being serialized or deserialized correctly. The primary reasons for this could be:
The Exception class does not correctly implement the ISerializable pattern.
The assembly which contains the Exception class is not present on the client, so the client does not understand how to create the Exception type.
In this case, I would lean towards the second reason, because most (but not all!) Exception classes do correctly implement the ISerializable pattern.
In either case, you can catch your exception and turn it into a generic exception.
You could create a helper method to do this using the LogFormatter.PrintException(Exception) method from Orleans to format the exception as a string.
public static void ThrowPlainException(Exception e) =>
throw new Exception(Orleans.Runtime.LogFormatter.PrintException(e));
The solution I came to was to create a custom exception class that serializable add the database values object to it and bubble that up to the views.
[Serializable]
public class UpdateException : Exception
{
public object databaseValues { get; set; }
public UpdateException(object databaseValues)
{
this.databaseValues = databaseValues;
}
public UpdateException(string message, object databaseValues) :base(message)
{
this.databaseValues = databaseValues;
}
}
I am working on a framework that I have been building/planning for a month now. I have started to develop it and need some expertise guidance on how to structure it, I think i am either designing it wrong or simply overcomplicating it.
So the main project at the moment is a class library and it is split into the following:
Framework, Core etc (These house all extension methods and other useful goodies)
BusinessEntities (All the entity framework Entities, including configuration for entities, using Fluent API)
BusinessLogicLayer
DataAccessLayer
Now all entities inherit from BaseEntity which also inherits IValidableObject. BaseEntity looks like this:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace uk.BusinessEntities
{
public abstract class BaseEntity : IValidatableObject
{
public int PrimaryKey { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public abstract IEnumerable<ValidationResult> Validate(ValidationContext validationContext);
}
}
Then for the DataAccessLayer each class inherits the GenericObject class which looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
namespace uk.DataAccessLayer
{
public class GenericObject<T> where T : class
{
public GenericObject() { }
public static bool Add(T Entity, out IList<string> validationErrors)
{
using (var db = new DatabaseContext())
{
validationErrors = new List<string>();
try
{
db.Set<T>().Add(Entity);
db.SaveChanges();
return true;
}
catch (Exception ex)
{
InsertValidationErrors(ex, validationErrors);
return false;
}
}
}
public static IList<T> Retrieve()
{
using (var db = new DatabaseContext())
{
IList<T> Query = (IList<T>)(from x in db.Set<T>()
select x).ToList<T>();
return Query;
}
}
public static bool Update(T Entity, out IList<string> validationErrors)
{
validationErrors = new List<string>();
using (var db = new DatabaseContext())
{
try
{
db.Set<T>().Attach(Entity);
db.Entry(Entity).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
return true;
}
catch (Exception ex)
{
InsertValidationErrors(ex, validationErrors);
return false;
}
}
}
public static bool Delete(T Entity, out IList<string> validationErrors)
{
validationErrors = new List<string>();
using (var db = new DatabaseContext())
{
try
{
db.Entry(Entity).State = System.Data.Entity.EntityState.Deleted;
db.SaveChanges();
return true;
}
catch(Exception ex)
{
InsertValidationErrors(ex, validationErrors);
return false;
}
}
}
protected static void InsertValidationErrors(Exception ex, IList<string> validationErrors)
{
validationErrors.Insert(0, ex.Message);
if (ex.InnerException != null)
{
validationErrors.Insert(0, ex.InnerException.Message);
validationErrors.Insert(0, ex.InnerException.StackTrace);
}
}
}
}
Now my main point lies all with validation of the entities. For example we got two entities Page and PageURLS URLS are stored separately for pages.
Now when adding a Page the PageURL also needs to be added as well, so if a developer called
PageDAL.AddPage(page, errors)
Would you also expect this method to also add the URL automatically or should this be a separate call?
Any help on this would be greatly appreciated.
I would suggest using the validation used by EF by default (link). With this approach you can also set validation error messages, and even localize them. Exception error messages aren't usually really useful to endusers. In addition, an exception when saving doesn't necessarily mean that validation failed. It could be that something else went wrong.
EF really does a good job of adding object graphs to the database. So I would let it do its job. So yes, have the PageDAL.Add(page) also add the page urls, since it's really the same operation in the end. I don't see a reason to be more explicit.
Unfortunately these kind of questions usually can't be answered objectively. For me it's always a struggle between YAGNI and adhering to all the principles. It really depends on the system you're building and on your own point of view.
I already made lots of mistakes in either on or the other direction. Talk to your peers, especially the ones that will work on the project with you, figure something out, and don't be afraid to adapt on the way...
I'm sorry if this answer isn't really satisfactory.
Regarding validation, I would perform some validations (simple, not business oriented) in the Controller to reject simple wrong inputs in case they were not caught on the client-side (or if the client-side validations were skipped). Then I would validate the entities in the Business Layer and return a custom object with a validation result and a list of validation messages.
I think you're not considering transactions and that's why you don't know how to deal with 2 related entities. For example:
public static bool Delete(T Entity, out IList<string> validationErrors)
{
validationErrors = new List<string>();
using (var db = new DatabaseContext())
{
try
{
db.Entry(Entity).State = System.Data.Entity.EntityState.Deleted;
db.SaveChanges();
return true;
}
catch(Exception ex)
{
InsertValidationErrors(ex, validationErrors);
return false;
}
}
}
You are creating a Database context, inserting an entity and disposing the context. If you need to insert many entities and the second entity fails, what would you do? the way you are doing it, the first entity will be saved and the second one would not be saved. You should read about Unit of Work pattern so you can create a transaction accross operations.
Take a look at these articles:
Read these articles:
1) https://msdn.microsoft.com/en-us/library/hh404093.aspx
2) http://www.asp.net/mvc/overview/older-versions-1/models-%28data%29/validating-with-a-service-layer-cs
3) http://blog.diatomenterprises.com/asp-net-mvc-business-logic-as-a-separate-layer/
4) http://sampathloku.blogspot.com.ar/2012/10/how-to-use-viewmodel-with-aspnet-mvc.html
I may be going about this incorrectly but this is my class that I wrap my entity object:
using System;
using System.Linq;
namespace SSS.ServicesConfig.data
{
public partial class GlobalSetting
{
private static GlobalSetting _globalSettings;
public static GlobalSetting GlobalSettings
{
get
{
if (_globalSettings == null)
{
GetGlobalSetting();
}
return _globalSettings;
}
}
private static void GetGlobalSetting()
{
try
{
using (var subEntities = PpsEntities.DefaultConnection())
{
_globalSettings = (from x in subEntities.GlobalSettings
select x).FirstOrDefault();
if (_globalSettings == null)
{
_globalSettings = new GlobalSetting();
_globalSettings.GlobalSettingId = Guid.NewGuid();
_globalSettings.CompanyCode = string.Empty;
_globalSettings.CorporationId = Guid.Empty;
_globalSettings.DefaultBranch = "01";
_globalSettings.SourceId = Guid.Empty;
_globalSettings.TokenId = Guid.Empty;
subEntities.AddToGlobalSettings(_globalSettings);
subEntities.SaveChanges();
}
}
}
catch (Exception ex)
{
Logging.Log("An error occurred.", "GetGlobalSetting", Apps.ServicesConfig, ex);
throw new Exception(string.Format("Unable to retrieve data: [{0}].", ex.Message));
}
}
internal static void SaveGlobalSettings()
{
using (var entities = PpsEntities.DefaultConnection())
{
entities.Attach(_globalSettings);
entities.SaveChanges();
}
}
}
}
I'm trying to make it where they have to go through my class to get the settings record and save it though the same class. This is in a separate project that several other projects are going to import.
My save isn't saving to the database and I see no errors or changes on the record. In this particular table, there is only one record so it's not adding another record either.
Any suggestions?
First your save is not being called after the initial value is assigned to _globalSettings.
Second You should not be trying to change the value with a get accessor. It is bad form.
http://msdn.microsoft.com/en-us/library/w86s7x04.aspx
I recommend that you separate the responsibility of the save to the database to a new method (you could expose the SaveGlobalSettings method by making it public), but if you are determined to obfuscate the save from the user, then I would recommend you remove the save to the database from get accessor of the GlobalSettings property, create a set accessor for the GlobalSettings property, and put the save to the database in the GlobalSettings properties set accessor.
One other note, you are killing your stack trace.
throw new Exception(string.Format("Unable to retrieve data: [{0}].", ex.Message));
You can still catch and log the exception the way that your are doing it, but re-throw the exception like this:
catch (Exception ex)
{
Logging.Log("An error occurred.", "GetGlobalSetting", Apps.ServicesConfig, ex);
throw;
}
This will preserve the original exception.
I want to create a plug in that will create a record based on the specific format that can be found on the email body. For example:
PO/Dustine/Tolete/8:45 PM/Sample Location/sample desc
So far, I have this code:
using System;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Xrm;
public class Plugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
Entity entity;
// Check if the input parameters property bag contains a target
// of the create operation and that target is of type Entity.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
// Obtain the target business entity from the input parameters.
entity = (Entity)context.InputParameters["Target"];
// Verify that the entity represents a contact.
if (entity.LogicalName != "email") { return; }
}
else
{
return;
}
try
{
IOrganizationServiceFactory serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(
typeof(IOrganizationServiceFactory));
IOrganizationService service =
serviceFactory.CreateOrganizationService(context.UserId);
var id = (Guid)context.OutputParameters["id"];
AddNewServiceRequest(service, id);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException(
"An error occurred in the plug-in.", ex);
}
}
private static void AddNewServiceRequest(IOrganizationService service, Guid id)
{
using (var crm = new XrmServiceContext(service))
{
var email = crm.EmailSet.Where(c => c.ActivityId == id).First();
string[] noteText = email.Description.ToString().Split('/');
foreach(string text in noteText){
Console.WriteLine(text);
}
Entity peaceAndOrder = new Entity("msa_noisecomplaintrequest");
peaceAndOrder["msa_firstname"] = noteText[1];
peaceAndOrder["msa_lastname"] = noteText[2];
peaceAndOrder["msa_incidenttime"] = noteText[3];
peaceAndOrder["msa_location"] = noteText[4];
peaceAndOrder["msa_description"] = noteText[5];
service.Create(peaceAndOrder);
}
}
}
But everytime the event is triggered, an error is occurring. What am I doing wrong?
You’re using context.OutputParameters to get the email Id. I assume that your plug-in is registered on a post create event.
Ensure that step is indeed registered properly (i.e. running on the post event) and that there are no other plug-in running on the email entity.
If you do have other plug-ins running on email (such as a pre event plug-in) you must wrap your code with a proper condition ensuring this only runs on post create event i.e.
if (context.Stage == 40 /*Post Operation*/)
{
// Your code here …
}
It’s also good practice to wrap your code with a condition checking the correct message name i.e.
if (context.MessageName == "CREATE")
{
// Your code here …
}
As a side note, you defined AddNewServiceRequest as static. plug-ins are Cached by CRM so they are static in a sense. You don’t need to declare static member
in your code unless you intend to share data between plug-ins or when declaring static members inside objects.
And finally, enable platform tracing or debug to get a glimpse of what really causing this.