Entity Framework Code First DBContext ObjectStateManager Error - ef-code-first

I am getting an Error "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key."
public class TestObject
{
public string Name {get;set;}
}
public EditTeamResponse Edit(TestObject testObject)
{
if (!ValidateTestObject(testObject))
{
return testObject;
}
try
{
_unitOfWork.TestObjectRepository.Update(testObject);
_unitOfWork.Commit();
}
catch (Exception)
{
//Error is thrown here
_validationDictionary.AddError("Unknown", "Unknown Error!");
return testObject;
}
// Other Extra Code
return editTeamResponse;
}
protected bool ValidateTestObject(TestObject testObject)
{
if (CheckIfNameChanged(teamToValidate))
{
if (_unitOfWork.TestObjectRepository.Any(x => x.Name == testObject.Name))
_validationDictionary.AddError("Name", "Name already exist.");
}
return _validationDictionary.IsValid;
}
private bool CheckIfNameChanged(TestObject testObject)
{
return _unitOfWork.TestObjectRepository.FindBy(testObject.TeamId).Name != testObject.Name;
}
I know that when I call CheckIfNameChanged(TestObject testObject) method i added an Entity Key to the ObjectContext and when i attach or edit the code when i call the _unitOfWork.TestObjectRepository.Update(testObject):
public void Update{
_context.Entry(entity).State = EntityState.Modified;
}
This is where the conflict happen and i got two same entity key in the ObjectStateManager. Is there a way to solve this problem without me going to the Context to detach the entity or is there some other way? And what is the best way to detach an entity from the context?

You can check if name changed as follows
private bool CheckIfNameChanged(TestObject testObject)
{
return !_unitOfWork.TestObjectRepository
.Any(x => x.TeamId == testObject.TeamId && x.Name == testObject.Name);
}

Related

Fluent Validation - Custom Guid Validator not triggering

I have a custom FleuntValidation validationrule that checks if a Guid is valid;
public static class GuidValidator
{
private static Regex isGuid = new Regex(#"^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$", RegexOptions.Compiled);
public static bool IsGuid(string candidate)
{
if (candidate != null)
{
if (isGuid.IsMatch(candidate))
{
return true;
}
}
return false;
}
}
I want to use this to check a Guid Property for a valid Guid and then return a custom error message.
RuleFor(x => x.ShiftId).Must(guid => GuidValidator.IsGuid(guid.ToString())).WithMessage("StopShift.ShiftId.GuidNotValid()");
However, my rule does not get hit, because i guess the Guid is not valid and some built in check runs before it. How would i disable the built-in check so my custom rule gets reached?
It depends on what your stack looks like. A Guid will not be instantiated with an "invalid" value.
If you want to cater for a use case where the value in question can either be a valid or invalid Guid I suggest you model it as a string.
e.g.
[Validator(typeof(FooRequestValidator))]
public class FooRequest
{
public string Bar { get; set; }
}
public class FooRequestValidator : AbstractValidator<FooRequest>
{
public FooRequestValidator()
{
RuleFor(x => x.Bar)
.Must(ValidateBar).WithErrorCode("Not a guid");
}
private bool ValidateBar(string bar)
{
return Guid.TryParse(bar, out var result);
}
}
Property in the class is a non-nullable Guid.
public Guid ProductId {get;set;}
Here is what I use
RuleFor(product => product.ProductId).Must(BeAValidGuid).When(product => product.ProductId != null);
With the Custom Rule
private bool BeAValidGuid(Guid unValidatedGuid)
{
try
{
if(unValidatedGuid != Guid.Empty && unValidatedGuid != null )
{
if (Guid.TryParse(unValidatedGuid.ToString(), out Guid validatedGuid))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
catch (Exception)
{
throw;
}
}

aspnet core controller datetime parameter bypasses modelvalid check

I have a number of controllers of this form:
public IActionResult GetSomething(int id, DateTime from) {
...
}
The id and from parameters are given on the query as query parameters. If id is not supplied, the ModelValid state is set to false. But if from is not supplied, ModelValid is true and from is set to 1900-01-01 00:00:00 (DateTime.Min).
How do I make ModelState false if a wanted DateTime parameter isn't supplied?
I decided to go for implementing a DateTime model binder. The following code will not set IsValid=true on ModelState if the DateTime argument is missing. DateTime? (nullable DateTime) is handled fine, but again, if the query parameter is missing, IsValid is set to false instead of setting the parameter to a default value.
First the DateTimeModelBinderProvider:
public class DateTimeModelBinderProvider : IModelBinderProvider
{
/// <inheritdoc />
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (!context.Metadata.IsComplexType)
{
// We can handle DateTime and nullable DateTime
if ((context.Metadata.ModelType == typeof(DateTime)) ||
(context.Metadata.IsNullableValueType && context.Metadata.UnderlyingOrModelType == typeof(DateTime)))
return new DateTimeModelBinder(context.Metadata.ModelType);
}
return null;
}
}
Next the DateTimeModelBinder. Most of the code is copied verbatim from github. Some of it could be left out, but it works as it is:
public class DateTimeModelBinder : IModelBinder
{
private readonly TypeConverter _typeConverter;
public DateTimeModelBinder(Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
_typeConverter = TypeDescriptor.GetConverter(type);
}
/// <inheritdoc />
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == ValueProviderResult.None)
{
// Do not accept an empty value provider result as being ok for DateTime (is ok for DateTime?)
bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName,
bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
valueProviderResult.ToString()));
// no entry
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
try
{
var value = valueProviderResult.FirstValue;
object model = null;
if (!string.IsNullOrWhiteSpace(value))
{
model = new DateTimeConverter().ConvertFrom(
context: null,
culture: valueProviderResult.Culture,
value: value);
}
if (bindingContext.ModelType == typeof(string))
{
var modelAsString = model as string;
if (bindingContext.ModelMetadata.ConvertEmptyStringToNull &&
string.IsNullOrEmpty(modelAsString))
{
model = null;
}
}
// When converting newModel a null value may indicate a failed conversion for an otherwise required
// model (can't set a ValueType to null). This detects if a null model value is acceptable given the
// current bindingContext. If not, an error is logged.
if (model == null && !bindingContext.ModelMetadata.IsReferenceOrNullableType)
{
bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName,
bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
valueProviderResult.ToString()));
return Task.CompletedTask;
}
else
{
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
catch (Exception exception)
{
var isFormatException = exception is FormatException;
if (!isFormatException && exception.InnerException != null)
{
// TypeConverter throws System.Exception wrapping the FormatException,
// so we capture the inner exception.
exception = ExceptionDispatchInfo.Capture(exception.InnerException).SourceException;
}
bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName,
exception,
bindingContext.ModelMetadata);
// Were able to find a converter for the type but conversion failed.
return Task.CompletedTask;
}
}
}
Also remember to activate it. I insert it at the start of the provider list to ensure my DateTime provider is used in preference of the default handler:
var mvc = services.AddMvc(config => {
config.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());
});
You can solve this issue by creating a model that has a validation attribute for the 'From' property.
I havent tested out the code. But code should be like:
public class Model
{
public int Id { get; set; }
[DateTimeShouldHaveValue]
public DateTime From { get; set; }
}
public class DateTimeShouldHaveValueAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null)
return false;
var dateTimeTmp = value.ToString();
DateTime dateTime;
DateTime.TryParse(dateTimeTmp, out dateTime);
if (dateTime == DateTime.MinValue)
return false;
return true;
}
}
public IActionResult GetSomething(Model model)
{
}

Robolectric packagemanager doesn't return correct value for getNameForUid?

I keep getting null, even though the package is added. I looked at the source, turns out StubPackageManager is always returning null for that and there is no way to override the entire PackageManager class.
In setup:
MockPackageManager mockPackageManager = new MockPackageManager(
Robolectric.getShadowsAdapter());
RuntimeEnvironment.setRobolectricPackageManager(mockPackageManager);
Subclass:
class MockPackageManager extends DefaultPackageManager {
public MockPackageManager(ShadowsAdapter shadowsAdapter) {
super(shadowsAdapter);
}
#Override
public String getNameForUid(int uid) {
switch (uid) {
case UID_A:
return NAME_A;
case UID_B:
return NAME_B;
default:
return null;
}
}
#Override
public boolean isPermissionRevokedByPolicy(String s, String s1) {
return false;
}
}

How do you abstract page session properties?

I was following this example
example code:
public class Global : HttpApplication
{
private Poster _posterDetails;
private Posting _postingDetails;
private Property _propertyDetails;
protected void Application_PostRequestHandlerExecute(object sender, EventArgs e)
{
if (HttpContext.Current.Session == null) return;
_posterDetails = HttpContext.Current.Session["Poster"] as Poster;
_postingDetails = HttpContext.Current.Session["Posting"] as Posting;
_propertyDetails = HttpContext.Current.Session["Property"] as Property;
}
}
these session variables are littered throughout the app and I need to abstract the retrieval of them. Say, later I get them from a db instead of the current session.
Session is baked into the Page or Context. How do I inject that dependency into the concrete implementation of a possible current property getter.
Create an abstraction around HttpContext:
public interface IHttpContextFactory
{
HttpContextBase Create();
}
public class HttpContextFactory
: IHttpContextFactory
{
public HttpContextBase Create()
{
return new HttpContextWrapper(HttpContext.Current);
}
}
Then inject it into a specialized service for these settings.
public interface ISettings
{
T GetValue<T>(string key);
void SetValue<T>(string key, T value);
}
public class ContextSettings
: ISettings
{
private readonly IHttpContextFactory httpContextFactory;
private HttpContextBase context;
public RequestCache(
IHttpContextFactory httpContextFactory
)
{
if (httpContextFactory == null)
throw new ArgumentNullException("httpContextFactory");
this.httpContextFactory = httpContextFactory;
}
protected HttpContextBase Context
{
get
{
if (this.context == null)
{
this.context = this.httpContextFactory.Create();
}
return context;
}
}
public virtual T GetValue<T>(string key)
{
if (this.Context.Session.Contains(key))
{
return (T)this.Context.Session[key];
}
return default(T);
}
public virtual void SetValue<T>(string key, T value)
{
this.Context.Session[key] = value;
}
}
It will later be possible to replace the service with another storage mechanism by implementing ISettings and providing different constructor dependencies. Note that changing the constructor signature does not require a different interface.
That said, you should provide another service (or perhaps more than one) that takes ISettings as a dependency so you can make explicit properties. You should aim to provide focused sets of related properties for specific purposes. Your application also shouldn't have to know the type of property in order to retrieve its value - it should just call a property that hides those details.
public class SomeSettingsService: ISomeSettingsService
{
private readonly ISettings settings;
public SomeSettingsService(ISettings settings)
{
if (settings == null)
throw new ArgumentNullException("settings");
this.settings = settings;
}
public Poster Poster
{
get { return this.settings.GetValue<Poster>("Poster"); }
set { this.settings.SetValue<Poster>("Poster", value); }
}
public Posting Posting
{
get { return this.settings.GetValue<Posting>("Posting"); }
set { this.settings.SetValue<Posting>("Posting", value); }
}
public Property Property
{
get { return this.settings.GetValue<Property>("Property"); }
set { this.settings.SetValue<Property>("Property", value); }
}
}
Not sure if this is what you are asking... What I often do is create a service:
public interface ISessionService
{
object Get(string key);
void Save(string key, object value);
}
And then I implement this, which calls HttpContext.Current.Session[key] and returns the value. It shouldn't be hard to create a Get<T>(string key) to return an object either. Break all of your dependencies to use this (which is the hard part).
There is no seamless way to break the dependency... it has to be through a manual change.

How to modify ILookup object in C# 4.0?

Before .NET 3.5 was released, I use
Dictionary<TKey, List<TValue>>
for containing data. But I just found that .NET 3.5 provides new collection type that is ILookup class that can represent my old complex data type.
I always create ILookup object by using LINQ extension method (ToLookup method). But I do not know how to modify ILookup object.
Is it possible? Or I need to create by using union method and call ToLookup method again.
Thanks,
You don't, it's immutable. You have listed both of the reasonable options; either to use a dictionary of sub-collections or to keep creating new lookups.
Here is an example of an implementation of ILookup that can be manipulated. It wraps around a Dictionary of List's of elements. It is completely generic. I couldn't think of a better name. :)
public class LookupDictionary<TKey, TElement> : ILookup<TKey, TElement>
{
private Dictionary<TKey, List<TElement>> _dicLookup = new Dictionary<TKey, List<TElement>>();
public LookupDictionary()
{
}
public LookupDictionary(ILookup<TKey, TElement> a_lookup)
{
foreach (var grouping in a_lookup)
{
foreach (var element in grouping)
AddElement(grouping.Key, element);
}
}
public IEnumerable<TElement> AllElements
{
get
{
return (from key in _dicLookup.Keys
select _dicLookup[key])
.SelectMany(list => list);
}
}
public int Count
{
get
{
return AllElements.Count();
}
}
public IEnumerable<TElement> this[TKey a_key]
{
get
{
List<TElement> list;
if (_dicLookup.TryGetValue(a_key, out list))
return list;
return new TElement[0];
}
}
public bool Contains(TKey a_key)
{
return _dicLookup.ContainsKey(a_key);
}
public void Add(TKey a_key, TElement a_element)
{
AddElement(a_key, a_element);
}
public void RemoveKey(TKey a_key)
{
_dicLookup.Remove(a_key);
}
public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator()
{
return GetGroupings().GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return (GetGroupings() as System.Collections.IEnumerable).GetEnumerator();
}
private void AddElement(TKey a_key, TElement a_element)
{
List<TElement> list;
if (!_dicLookup.TryGetValue(a_key, out list))
{
list = new List<TElement>();
_dicLookup.Add(a_key, list);
}
list.Add(a_element);
}
private IEnumerable<IGrouping<TKey, TElement>> GetGroupings()
{
return from key in _dicLookup.Keys
select new LookupDictionaryGrouping<TKey, TElement>
{
Key = key,
Elements = _dicLookup[key]
} as IGrouping<TKey, TElement>;
}
}
public class LookupDictionaryGrouping<TKey, TElement> : IGrouping<TKey, TElement>
{
public TKey Key
{
get;
set;
}
public IEnumerable<TElement> Elements
{
get;
set;
}
public IEnumerator<TElement> GetEnumerator()
{
return Elements.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return (Elements as System.Collections.IEnumerable).GetEnumerator();
}
}
As mquander mentioned, the lookup is immutable. However, you can build a new lookup with additional or removed values.
// Add a new value
myLookup = myLookup
.SelectMany(l => l.Select(v => new {l.Key, Value = v}))
.Union(new[] {new {Key = myNewKey, Value = myNewValue}})
.ToLookup(a => a.Key, a => a.Value);
// Remove an old value
myLookup = myLookup
.SelectMany(l => l.Select(v => new {l.Key, Value = v}))
.Where(a => a.Value != myOldValue)
.ToLookup(a => a.Key, a => a.Value);

Resources