Cannot serialize ISession when using Newtonsoft.Json library - c#

my program is displaying the following error when trying to save some data without saving it to database and displaying it in json.
Newtonsoft.Json.JsonSerializationException: 'Could not create an instance of type Microsoft.AspNetCore.Http.ISession. Type is an interface or abstract class and cannot be instantiated. Path 'Session.IsAvailable', line 1, position 26.'
My Error Pic
This code is written using a repository design template.
The code written in the comment works. Should I change the code GetJson<T> in the new version? after change using Newtonsoft.Json TO using System.Text.Json.Serialization?
public class CartController : Controller
{
private IProductRepository repository;
private Cart _cart;
public CartController(IProductRepository repo, Cart cart)
{
repository = repo;
_cart = cart;
}
public ViewResult Index(string returnurl)
{
ViewBag.ReturnUrl = returnurl;
//return View(GetCart());
return View(_cart);
}
public IActionResult AddToCart(int ProductID,string returnUrl)
{
Product product = repository.GetById(ProductID);
if (product != null)
{
//Cart cart = GetCart();
//cart.AddItem(product, 1);
//SaveCart(cart);
_cart.AddItem(product, 1);
}
return RedirectToAction("Index", new { returnUrl });
}
public IActionResult RemoveFromCart(int ProductID, string returnUrl)
{
Product product = repository.GetById(ProductID);
if (product != null)
{
//Cart cart = GetCart(); //-----> Worked
//cart.RemoveLine(product); //-----> Worked
//SaveCart(cart); //-----> Worked
_cart.RemoveLine(product); //Not Working
}
return RedirectToAction("Index", new { returnUrl });
}
//private Cart GetCart() //-->Worked
//{
// Cart cart = HttpContext.Session.GetJson<Cart>("Cart") ?? new Cart();
// return cart;
//}
//private void SaveCart(Cart cart) //-->Worked
//{
// HttpContext.Session.SetJson("Cart", cart);
//}
}
public static class SessionExtensions
{
public static void SetJson(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetJson<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) :
JsonConvert.DeserializeObject<T>(value); //error exception throw here
}
}
and:
public class SessionCart : Cart
{
public static Cart GetCart(IServiceProvider services)
{
ISession session = services.GetRequiredService<IHttpContextAccessor>()?.HttpContext.Session;
SessionCart cart = session?.GetJson<SessionCart>("Cart") ?? new SessionCart();
cart.Session = session;
return cart;
}
[JsonIgnore]
public ISession Session { get; set; }
public override void AddItem(Product product, int quantity)
{
base.AddItem(product, quantity);
Session.SetJson("Cart", this);
}
public override void RemoveLine(Product product)
{
base.RemoveLine(product);
Session.SetJson("Cart", this);
}
public override void Clear()
{
base.Clear();
Session.Remove("Cart");
}
}

you must remove system.Text.Json.Serialization
and add using Newtonsoft.Json in SessionCart

Just add the following namespace to the SessionCart class.
using Newtonsoft.Json;

I see you are following the Pro ASP.NET Core 2 MVC book by Adam Freeman.
To fix this issue, change the access modifier on the ISession variable from public to private. This will prevent the ISession being serialized and will then deserialize as you would expect.
Before:
[JsonIgnore]
public ISession Session { get; set; }
After:
private ISession session { get; set; }
Then ensure all of your methods can use the lowercase session (to follow naming convention best practice).

Related

Get parameter custom mapping

I want to write many GET handlers that receive an ID for an object,
site.com/controller/Action1/1234
site.com/controller/Action2/1234
site.com/controller/Action3/1234
I would like to write the code that fetches the complex object from the DB just once:
class ComplexObject
{
public string str1 { get; set; }
public string str2 { get; set; }
}
ComplexObject GetFromId(string id)
{
ComplexObject x = Database.GetById(id);
if (x == null)
{
return Http404();
}
return x;
}
and then just use the object directly:
[Route("/[controller]/[action]/{message}")]
[HttpGet]
public string Action1(ComplexObject message)
{
return message.str1;
}
[Route("/[controller]/[action]/{message}")]
[HttpGet]
public string Action2(ComplexObject message)
{
return message.str1;
}
[Route("/[controller]/[action]/{message}")]
[HttpGet]
public string Action3(ComplexObject message)
{
return message.str1;
}
And that all of my handlers will just get the object, and won't have to check whether the ID is correct, etc.
How is that possible?
The official Microsoft Docs describe exactly how you can bind route parameters to a complex object from a database using a custom model binder.
Here's their example model binder:
public class AuthorEntityBinder : IModelBinder
{
private readonly AuthorContext _context;
public AuthorEntityBinder(AuthorContext context)
{
_context = context;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
// Try to fetch the value of the argument by name
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}
if (!int.TryParse(value, out var id))
{
// Non-integer arguments result in model state errors
bindingContext.ModelState.TryAddModelError(
modelName, "Author Id must be an integer.");
return Task.CompletedTask;
}
// Model will be null if not found, including for
// out of range id values (0, -3, etc.)
var model = _context.Authors.Find(id);
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
And then there are various ways to use this new model binder. One is to add an attribute on the model itself:
[ModelBinder(BinderType = typeof(AuthorEntityBinder))]
public class Author
{
// snip
}
Another is to use an attribute on the action parameters:
[HttpGet("{id}")]
public IActionResult GetById([ModelBinder(Name = "id")] Author author)
{
// snip
}
I am not sure why one would want to do what you are proposing, but it unnecessarily overcomplicates things and causes dependencies on the model binder.
Here is how I would implement this:
Have a class that manages your complex object and hide it behind an interface, the inject it into the controller:
public interface IComplexObjectManager
{
ComplexObject GetFromId(string id);
}
public class ComplexObjectManager : IComplexObjectManager
{
private readonly Database _database;
public ComplexObjectManager(Database database)
{
_database = database;
}
public ComplexObject GetFromId(string id)
{
ComplexObject x = _database.GetById(id);
return x;
}
}
[ApiController]
public class ComplexObjectController
{
public ComplexObjectController(IComplexObjectManager complexObjectManager)
{
ObjectManager = complexObjectManager;
}
public IComplexObjectManager ObjectManager { get; }
}
Then consume it in your method, changing the return type to an action result:
[Route("/[controller]/[action]/{id}")]
[HttpGet]
public IActionResult Action1(string id)
{
var obj = ObjectManager.GetFromId(id);
if(obj != null)
return Ok(obj.str1);
else
return NotFound();
}
Make sure to handle the response accordingly.
This approach decouples things (further abstraction can be added for Database), and allows for injection and unit testing.
Please check the code for consistency. I wrote this in a hurry.
I'm not doing the exactly thing that you are asking but i think it can help you. First of all, i'm using BaseController for it because you can filter your all actions before they are getting executed.
public class BaseController : Controller
{
#region /*IoC*/
public BaseViewModel baseViewModel;
public IUnitOfWork<Product> unitOfWorkProductForCart;
#endregion
#region /*ctor*/
public BaseController(IUnitOfWork<Product> unitOfWorkProductForCart)
{
this.unitOfWorkProduct = unitOfWorkProduct;
}
#endregion
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string controllerName = filterContext.ActionDescriptor.RouteValues["controller"];
string actionName = filterContext.ActionDescriptor.RouteValues["action"];
if (actionName == "ProductDetails")
{
var urlParameters = filterContext.ActionArguments;
if (urlParameters.Count != 0)
{
var isThatSlug = urlParameters.ElementAt(0).Key;
if (isThatSlug == "slug")
{
var slugCondition = urlParameters.ElementAt(0).Value;
var isThatProductExist = unitOfWorkProduct.RepositoryProduct.GetProductBySlugForChecking(slugCondition.ToString());
if (isThatProductExist.Count == 0)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary
{
{"controller","Account"},
{"action","NotFound"}
});
}
}
}
}
}
}
in that example, i'm controlling the parameters. if it's something like i don't want, it's redirects you to the NotFound page.
i hope it can give you a idea

Validations and passing ModelState from Service Layer to Controller WebAPI

I was following the below link to get the validations done at Service Layer
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/models-data/validating-with-a-service-layer-cs
I ended up having cyclic dependency. So remove dependency injection of validation/ModelStateWrapper and used Initialize static way.
Brief Explanation about the Project: I have API, Services Layer, Repository, Database. I am using Automapper to map DTO's to Entities.
Controller:
public StudentController(IStudentService studentService, IMapper mapper)
{
_studentService = studentService;
_studentService.Initialize(new ModelStateWrapper(this.ModelState));
_mapper = mapper;
}
public IActionResult CreateStudent([FromBody] StudentCreationDto student)
{
if (student== null)
{
return BadRequest();
}
if (!ModelState.IsValid)
{
return new UnprocessableEntityObjectResult(ModelState);
}
var studentEnitty = _mapper.Map<Student>(student);
var createSuccessful = _studentService.CreateStudent(studentEnitty);
if (!createSuccessful)
{
return new UnprocessableEntityObjectResult(ModelState);
}
}
Service:
public void Initialize(IValidationDictionary validationDictionary)
{
_validationDictionary = validationDictionary;
}
public bool CreateStudent(Student student)
{
//Check if Student already exists
if (!ValidateStudentToCreate(student))
{
return false;
}
//Create Portal
var createSuccessful = _studentRepository.CreateStudent(student);
if (!createSuccessful)
{
return false;
}
return true;
}
private bool ValidateStudentToCreate(Student student)
{
//throw new Exception();
if (_studentRepository.StudentEmailExists(student.Email))
{
_validationDictionary.AddError("Email", "Student already exists");
}
bool isValid = _validationDictionary.IsValid;
return isValid;
}
I have IValidation dictionary with AddError and IsValid. ModelStateWrapper Implements IValidationDictionary.
IValidation Dictionary
public interface IValidationDictionary
{
void AddError(string key, string errorMessage);
bool IsValid { get; }
}
ModelStateWrapper
public class ModelStateWrapper : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateWrapper(ModelStateDictionary modelState)
{
_modelState = modelState;
}
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
public bool IsValid
{
get { return _modelState.IsValid; }
}
I am trying to get the data model validations at Controller level and Business logic such as Student exists at Service level. I am able to execute the validations however, i am unable to get the model state back to Controller as it says valid. Can you please let me know what I am missing?

Using DI with Entity Framework and multiple data contexts in ASP.NET MVC

I am wondering, how we can handle a situation, and if I'm going about this the wrong way. We wrote a web application based on one ERP's database schema model. We are using Entity Framework for the system, with the regular dependency injection method.
Now that we have purchased multiple ERP's from other labs, we are trying to allow their data be used on our first original web portal built for our original ERP. As you can imagine, this is rough as the database models and design will not line up with ours. For example something like GetAllAssets() stored procedure returns the complex type and then is bound to the repo level, the service level and onto the view.
What I was thinking is that we could maybe add multiple EDMX (context for databases), then keep everything from the Views to the controllers to the service layer the same. At the service layer, and type params to our classes, and so we could pass the context the current user logged in as, and then in auto mapper add new entries for the new database context calls from Entity Framework, to map to our original code from the service back down to the view.
Is this possible, and or a good idea or bad idea?
Here is a example of a current basic controller we are using with DI style, and I have removed a lot of code for this question's example:
[AuthorizeWithSession]
public class LocationController : Controller
{
private readonly IMProAssetLocationService _mProAssetLocationService;
private readonly IUIDataService _uiDataService;
public LocationController(IMProAssetLocationService mProAssetLocationService,
IUIDataService uiDataService)
{
_mProAssetLocationService = mProAssetLocationService;
}
public ActionResult List()
{
return View();
}
public ActionResult List2()
{
return View();
}
public ActionResult GetLocationList([DataSourceRequest]DataSourceRequest request)
{
//var result = DepartmentService.GetDepartmentList(SessionHelper.GetCustId());
var result = _mProAssetLocationService.MProAssetLocationGetLocationByCustID(SessionHelper.GetCustId(), null);
if (result != null && result.Any())
{
return Json(result.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
}
}
The interface service layer:
public interface IMProAssetLocationService
{
IEnumerable<LocationVm> MProAssetLocationGetLocationByCustID(string custId,string id);
string MProAssetLocationInsertLocation(LocationVm vm);
void MProAssetLocationDeleteLocationByCustIDAndLocationID(string custId, string locationId);
void MProAssetLocationUpdateLocationByCustIDAndLocationID(LocationVm vm);
}
The service layer:
public class MProAssetLocationService : LogManager, IMProAssetLocationService
{
private readonly IMProAssetLocationRepo _mProAssetLocationRepo;
public MProAssetLocationService(IMProAssetLocationRepo mProAssetLocationRepo)
{
_mProAssetLocationRepo = mProAssetLocationRepo;
}
protected override Type LogPrefix
{
get { return this.GetType(); }
}
public IEnumerable<LocationVm> MProAssetLocationGetLocationByCustID(string custId, string id)
{
List<LocationVm> listlocationVm = new List<LocationVm>();
try
{
var records = _mProAssetLocationRepo.MProAssetLocationGetLocationByCustID(custId,id);
}
}
The Interface repo layer:
public interface IMProAssetLocationRepo : IRepository<MProAssetLocation>
{
IEnumerable<string> GetMProAssetLocatonByCustId(string custId);
IEnumerable<string> GetMProAssetLocatonDescriptionByCustId(string custId);
IEnumerable<LocationView> GetMProAssetLocatonListByCustId(string search, string locationID, string custId);
IEnumerable<LocationView> MProAssetLocationGetLocationByCustID(string custId, string id);
string MProAssetLocationInsertLocation(LocationView lv);
void MProAssetLocationDeleteLocationByCustIDAndLocationID(string custId, string locationId);
void MProAssetLocationUpdateLocationByCustIDAndLoacationID(LocationView lv);
}
The repo layer:
public class CalLocationsRepo : RepositoryBase<CalLocaton>, ICalLocationsRepo
{
public CalLocationsRepo(IDbFactory dbFactory)
: base(dbFactory)
{
}
//WHERE CalCodeActive=1 AND CalCodeGroup='OSS' ORDER BY CalCode
public IEnumerable<string> GetCalLocations(string empID)
{
return DbContext.TAM_GetCalLocationsList(empID).ToList();
}
}
I was thinking of something like using a context type in our system. I know the entity models calls would be named differently based on our different databases using their own stored procedures, but thought at the level prior to the call i check the context to use, then make the call accordingly like so:
public class DBContextRepo<T> : RepositoryBase, IDBContextRepo<T>
{
DBContextRepo<T> _typeParameterClass;
public DBContextRepo(IDbFactory dbFactory, DBContextRepo<T> typeParameterClass)
: base(dbFactory)
{
_typeParameterClass = typeParameterClass;
}
public List<string> GetAllModelsByManufcaturer(string manufacturerName)
{
List<string> results = new List<string>();
if (_typeParameterClass.GetType() == typeof(TAM.DataLayer.EntityModels.QuoteWerks1Entities))
{
using(var dbContext = DbContextQw)
{
var items = dbContext.Products_OurProducts_Products.Where(p => p.Manufacturer == manufacturerName).ToList();
results = items.Select(p => p.ManufacturerPartNumber).ToList();
}
}
else
{
using (var dbContext = DbContext)
{
var items = dbContext.Models.Where(a => a.Manufacturer.MfrName == manufacturerName);
results = items.Select(m => m.ModelNumber).ToList();
}
}
return results;
}
}
This causes errors and is where im not sure how to handle two DBContext:
public class DbFactory : Disposable, IDbFactory
{
private TAMModel _dbContext;
private QuoteWerks1Entities _dbContextQW;
public TAMModel Init()
{
return _dbContext ?? (_dbContext = new TAMModel());
}
public QuoteWerks1Entities InitQW()
{
return _dbContextQW ?? (_dbContextQW = new QuoteWerks1Entities());
}
protected override void DisposeCore()
{
if (_dbContext != null)
{
_dbContext.Dispose();
}
if (_dbContextQW != null)
{
_dbContextQW.Dispose();
}
}
}
Once i added the second context, all of my regular code say they do not have a corresponding type in constructors such as this one:
public class ContractRepo : RepositoryBase<Contract>, IContractRepo
{
public ContractRepo(IDbFactory dbFactory)
: base(dbFactory)
{
}
public string GetContractIdentifyByCustId(string custId)
{
return DbContext.TAM_GetContractIdentifyByCustId(custId).SingleOrDefault();
}
}
Here is the BaseRepo class:
public class RepositoryBase
{
private readonly TAMModel _dataContext;
private readonly QuoteWerks1Entities _dataContextQW;
protected IDbFactory DbFactory { get; private set; }
protected TAMModel DbContext
{
get
{
return _dataContext ?? DbFactory.Init();
}
}
protected QuoteWerks1Entities DbContextQw
{
get
{
return _dataContextQW ?? DbFactory.InitQW();
}
}
protected RepositoryBase(IDbFactory dbFactory)
{
DbFactory = dbFactory;
}
}
public abstract class RepositoryBase<T> where T : class
{
private readonly TAMModel _dataContext;
private readonly IDbSet<T> _dbSet;
private readonly IDbSet<T> _dbSetQW;
private readonly QuoteWerks1Entities _dataContextQW;
protected IDbFactory DbFactory { get; private set; }
protected TAMModel DbContext
{
get
{
return _dataContext ?? DbFactory.Init();
}
}
protected QuoteWerks1Entities DbContextQW
{
get
{
return _dataContextQW ?? DbFactory.InitQW();
}
}
protected RepositoryBase(IDbFactory dbFactory, T type)
{
DbFactory = dbFactory;
_dbSet = DbContext.Set<T>();
_dbSetQW = DbContextQW.Set<T>();
}
public virtual void Add(T entity)
{
_dbSet.Add(entity);
}
public virtual void Update(T entity)
{
_dbSet.Attach(entity);
DbContext.Entry(entity).State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
_dbSet.Remove(entity);
}
public virtual void Delete(Expression<Func<T, bool>> where)
{
IEnumerable<T> objects = _dbSet.Where<T>(where);
foreach (T obj in objects)
{
_dbSet.Remove(obj);
}
}
public virtual T GetById(int id)
{
return _dbSet.Find(id);
}
public virtual T GetById(string id)
{
return _dbSet.Find(id);
}
public virtual IEnumerable<T> GetAll()
{
return _dbSet.ToList();
}
public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
{
return _dbSet.Where(where).ToList();
}
public T Get(Expression<Func<T, bool>> where)
{
return _dbSet.Where(where).SingleOrDefault();
}
public virtual IQueryable<T> Query()
{
return _dbSet;
}
public virtual IQueryable<T> Query(Expression<Func<T, bool>> where)
{
return _dbSet.Where(where);
}
public virtual ObjectQuery<U> CreateQuery<U>(string query, ObjectParameter[] parameters)
{
return CastAsObjectContext().CreateQuery<U>(query, parameters);
}
public virtual ObjectQuery<U> CreateQuery<U>(string query)
{
return CreateQuery<U>(query, new ObjectParameter[0] { });
}
public virtual ObjectQuery<DbDataRecord> CreateQuery(string query, ObjectParameter[] parameters)
{
return CreateQuery<DbDataRecord>(query, parameters);
}
public virtual ObjectQuery<DbDataRecord> CreateQuery(string query)
{
return CreateQuery<DbDataRecord>(query);
}
private ObjectContext CastAsObjectContext()
{
var oContext = (DbContext as IObjectContextAdapter).ObjectContext;
return oContext;
}
}
The only problem is, how do I set the context on a login when using dependency injection? Will this work, as at the moment I'm still in the process, or am I over complicating it and going about it the wrong way? Thanks in advance.

How to get my typed result in a custom filter attribute?

This is my code:
// Controller
[HttpGet("{id}")]
[MyFilter]
public async Task<MyCustomType> Load(string id)
{
return new MyCustomType(....);
}
// Custom attribute
public class MyFilterAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
// Can I have my MyCustomType result here?
}
}
I need to implement some special logic in case of specific property values of MyCustomType result.
Public class MyCustomType
{
// assuming that there will be more properties
public int Id { get; set; }
public string Name { get; set; }
}
// Now, Move to Controller method.
public class CustomController : Controller
{
[HttpGet({"id"})]
[MyFilter]
public async Task<MyCustomType> Load(string id)
{
// Do some async operations
// Or do some Db queries
// returning MyCustomType
MyCustomType typeToReturn = new MyCustomType();
typeToReturn.Id = 1;
typeToReturn.Name = "something";
return typeToReturn;
}
}
// Well here goes the attribute
public class MyFilterAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
// you have to do more digging i am using dynamic to get the values and result.
dynamic content = context.Result;
if (content != null)
{
dynamic values = content.Value;
}
}
}
EDIT changed the code and ran it in a dot net core project and i was able to get the values, how ever i have used dynamic you can dig more on it.

Crud operations with unit of work and generic repository

I am working on crud operations in mvc 4.0 with unitofwork and generic repository with Ninject for DI.
I am able to get a particular record from a table, I am even able to get all the records from the table.
but I am not able to insert a new record in the database table. I am not getting any error/exception and it is running each statement
cleanly but there is no effect in database below is my controller where I am using the repository and unitof work.
Can somebody tell me where I am wron or what code/statements I have left in this code. I ahve checked it lot of time and I am stucked now.
Not getting the problem
Controller:
private IUnitOfWork _unitOfWork;
private IRepository<tbl_Employee> _Repo;
private IRepository<tbl_Department> _Department;
public HomeController( IUnitOfWork UOW, IRepository<tbl_Employee> Repository, IRepository<tbl_Department> Depart)
{
this._unitOfWork = UOW;
this._Repo = Repository;
this._Department = Depart;
}
//This runs successfully and gets all the records in the view page and I am displaying all records using foreach in div structure
public ActionResult Index()
{
EmployeeModel ObjModel = new EmployeeModel();
ObjModel.Employees = this._Repo.GetALL();
//ObjModel.Employees = this._Employee.GetEmployees();
return View(ObjModel);
}
//This also runs successfully and it brought me a single record on selection of particular record from employee listing.
public ActionResult EmployeeDetail(string id)
{
EmployeeDetailModel ObjModel = new EmployeeDetailModel();
if (!string.IsNullOrEmpty(id))
{
var Employee = this._Repo.Find(Convert.ToInt32(id));
if (Employee != null)
{
ObjModel.InjectFrom(Employee);
}
}
return View(ObjModel);
}
// Here is the problem . Not able to insert the record. The model object is not empty . I have checked it and there is no error.It brought me a message
"Employee Created Successfully but in database there is no record.
public ActionResult SaveEmployee(EmployeeDetailModel Model)
{
string Msg = string.Empty;
try
{
tbl_Employee ObjEmployee = new tbl_Employee();
ObjEmployee.InjectFrom(Model);
if (Model.Male)
{
ObjEmployee.Sex = "m";
}
else
{
ObjEmployee.Sex = "f";
}
ObjEmployee.Department_Id = Model.Dept_id;
ObjEmployee.Salary = Convert.ToInt32(Model.Salary);
this._Repo.Insert(ObjEmployee);
this._unitOfWork.Commit();
Msg = "Employee Created Successfully";
}
catch
{
Msg = "Error occurred while creating the employee, Please try again.";
}
return Json(new { Message = Msg });
}
/// Repository interface
public interface IRepository<T> where T : class
{
void Insert(T entity);
void Delete(T entity);
void Update(T entity);
T Find(int key);
IEnumerable<T> GetALL();
}
Repository class
public class Repository<T> : Connection, IRepository<T> where T : class
{
private readonly DbSet<T> _dbSet;
public Repository()
{
_dbSet = _dbContext.Set<T>();
}
public void Insert(T entity)
{
_dbSet.Add(entity);
}
public void Delete(T entity)
{
_dbSet.Remove(entity);
}
public void Update(T entity)
{
var updated = _dbSet.Attach(entity);
_dbContext.Entry(entity).State = EntityState.Modified;
//_dataContext.Entry(item).State = EntityState.Modified;
}
public T Find(int Key)
{
var dbResult = _dbSet.Find(Key);
return dbResult;
}
public IEnumerable<T> GetALL()
{
return _dbSet;
}
}
UnitofWork Interface
public interface IUnitOfWork : IDisposable
{
void Commit();
}
Unit of work class
public class UnitOfWork : Connection, IUnitOfWork
{
private bool _disposed;
public void Commit()
{
_dbContext.SaveChanges();
}
public void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue to prevent finalization code for object from executing a second time.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!_disposed)
{
// If disposing equals true, dispose all managed and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
if (_dbContext != null)
{
_dbContext.Dispose();
}
}
}
_disposed = true;
}
}
My UnitofWork and Repository class derives from connection class where dbcontext is defined.
public abstract class Connection
{
protected db_TestEntities _dbContext;
public Connection()
{
this._dbContext = new db_TestEntities();
}
}
Is it that my dbContext is creating a new instance everytime like explained Here
and if yes then how can I resolve it.
tbl_Employee ObjEmployee = new tbl_Employee();
ObjEmployee.InjectFrom(Model);
if (Model.Male)
{
ObjEmployee.Sex = "m";
}
else
{
ObjEmployee.Sex = "f";
}
ObjEmployee.Department_Id = Model.Dept_id;
ObjEmployee.Salary = Convert.ToInt32(Model.Salary);
this._Repo.Insert(ObjEmployee);
After this, you should see your object mapped by EF in local memory.
this._unitOfWork.Commit();
Here your object should be pushed to database. dbContext.SaveChanges() return number of changed records which should be in your case 1.
Msg = "Employee Created Successfully";
Update:
So the problem is in your Connection class as you suggested.
I would create your DbContext in one place and then pass it to repository and unit of work. You could also create DbContext in unit of work constructor and then pass UOW to repository. This is one of my older implementation of this:
public class EntityFrameworkUnitOfWork : IUnitOfWork
{
private ForexDbContext dbContext;
internal ForexDbContext DbContext
{
get { return dbContext ?? (dbContext = new ForexDbContext()); }
}
internal DbSet<T> Set<T>()
where T : class
{
return DbContext.Set<T>();
}
public void Dispose()
{
if(dbContext == null) return;
dbContext.Dispose();
dbContext = null;
}
public void SaveChanges()
{
int result = DbContext.SaveChanges();
}
public ITransaction BeginTransaction()
{
return new EntityFrameworkTransaction(DbContext.BeginTransaction());
}
}
public class ContactsRepositoryWithUow : IRepository<Contact>
{
private SampleDbEntities entities = null;
public ContactsRepositoryWithUow(SampleDbEntities _entities)
{
entities = _entities;
}
public IEnumerable<Contact> GetAll(Func<Contact, bool> predicate = null)
{
if (predicate != null)
{
if (predicate != null)
{
return entities.Contacts.Where(predicate);
}
}
return entities.Contacts;
}
public Contact Get(Func<Contact, bool> predicate)
{
return entities.Contacts.FirstOrDefault(predicate);
}
public void Add(Contact entity)
{
entities.Contacts.AddObject(entity);
}
public void Attach(Contact entity)
{
entities.Contacts.Attach(entity);
entities.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
}
public void Delete(Contact entity)
{
entities.Contacts.DeleteObject(entity);
}
}
Please find answer in below link for more details
Crud Operation with UnitOfWork

Categories

Resources