How to configure Ninject in call scope binding within Azure Web Job? - dependency-injection

I am facing a problem when try to write a web job scheduler. I am using Ninject scope binding using EF Repository pattern. But Only InSingletonScope() work as expected. How to configure it in RequestScope Or Call Scope ?
//Register Context
Kernel.Bind<MyDbContext>().ToSelf().InSingletonScope();
Kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>().InSingletonScope();

Problem Solved From One of My Previous Post
I am posting Step By Step Solution
(1.) NinjectJobActivator
public class NinjectJobActivator : IJobActivator
{
#region Variable Declaration
private readonly IResolutionRoot _resolutionRoot;
#endregion
#region CONSTRUCTOR
/// <summary>
///
/// </summary>
/// <param name="kernel"></param>
// public NinjectJobActivator(IKernel kernel)
public NinjectJobActivator(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
#endregion
#region CreateInstance
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T CreateInstance<T>()
{
return _resolutionRoot.Get<T>(new CallScopedParameter());
}
#endregion
}
(2) NinjectBindings
using Ninject.Extensions.Conventions;
using Ninject.Extensions.NamedScope;
public class NinjectBindings : NinjectModule
{
public override void Load()
{
//Register Context
Kernel.Bind<MyDbContext>().ToSelf()
.When(x => x.Parameters.OfType<CallScopedParameter>().Any())
.InCallScope(); // For Scheduler
Kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>();
//Register Repository
Kernel.Bind(x => x
.FromAssemblyContaining<MyDbContext>()
.SelectAllClasses()
.InheritedFrom(typeof(IRepository<>))
.BindDefaultInterface());
}
}
(3) Program.cs
static void Main()
{
using (IKernel kernel = new StandardKernel(new NinjectBindings()))
{
var config = new JobHostConfiguration()
{
JobActivator = new NinjectJobActivator(kernel)
};
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
// Timer Trigger
config.UseTimers();
var host = new JobHost(config);
//// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
}
(4) CallScopedParameter
public sealed class CallScopedParameter : IParameter
{
/// <summary>
///
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public bool Equals(IParameter other)
{
if (other == null)
{
return false;
}
return other is CallScopedParameter;
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="target"></param>
/// <returns></returns>
public object GetValue(IContext context, ITarget target)
{
throw new NotSupportedException("this parameter does not provide a value");
}
/// <summary>
///
/// </summary>
public string Name
{
get { return typeof(CallScopedParameter).Name; }
}
/// <summary>
/// this is very important
/// </summary>
public bool ShouldInherit
{
get { return true; }
}
}
(5) Azure Web Job Function
public void DoSomething([TimerTrigger("*/30 * * * * *")] TimerInfo timer, TextWriter log)
{
try
{
var tempdetails = _sampleRepository.SearchFor(x=> DateTime.UtcNow > x.DateTo);
foreach (var detail in tempdetails)
{
if (detail.ID == 2)
{
detail.ID = 5;
}
_sampleRepository.Update(detail);
}
_unitOfWork.Commit();
}
catch (Exception ex)
{
log.WriteLine(ex.Message);
}
}

Related

How to make a common class for common code in a controller

I have two controllers both are derivated from a base controller. The code inside them is exactly the same. The only difference is in constructors. Below is my code:
[RoutePrefix("api/v2")]
public class CategoryController : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
/// <summary>
/// Constructor for initialization
/// </summary>
public CategoryController()
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
}
/// <summary>
/// Retrieve all Categories
/// </summary>
/// <returns>Categories(Id, Label)</returns>
[HttpGet]
[Route("categoryRef")]
public HttpResponseMessage Categories()
{
try
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest("categoryRef",null);
response = Request.CreateResponse(HttpStatusCode.OK, categories);
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
}
The second one is
[RoutePrefix("api/v2")]
public class ProblemCategoryController : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
/// <summary>
/// Constructor for initialization
/// </summary>
public ProblemCategoryController()
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
}
/// <summary>
/// Retrieve all Natures of problem
/// </summary>
/// <returns>Categories(Id, Label)</returns>
[HttpGet]
[Route("problemCategoryRef")]
public HttpResponseMessage ProblemCategories()
{
try
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest("problemCategoryRef", null);
response = Request.CreateResponse(HttpStatusCode.OK, categories);
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
Now as you can see the internal code is exactly the same which I want to avoid creating a Helper class. How can I make this common class for it so as to remove code duplicacy? It's possible without rewrite all the context code to get User and Id app?
I tried this
public class NatureOfProblemHelper : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
private string resourceName;
/// <summary>
/// Initializes a new instance of the <see cref="NatureOfProblemHelper"/> class.
/// Constructor for initialization.
/// <param name="resource">Resource requested by user.</param>
/// </summary>
public NatureOfProblemHelper(string resource)
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
resourceName = resource;
}
/// <summary>
/// Retrieve all Natures of problem.
/// </summary>
/// <returns>Categories(Id, Label).</returns>
public HttpResponseMessage GetNaturesOfProblem()
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest(resourceName, null);
return Request.CreateResponse(HttpStatusCode.OK, categories);
}
And then into each controller
[HttpGet]
[Route("problemCategoryRef")]
public HttpResponseMessage ProblemCategories()
{
try
{
response = natureOfProblem.NaturesOfProblem();
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
This build, but I can't get the context that comes from this variable
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
Why if I put the same lines of code directly in my controller works but if I put in my Helper it doesn't work??

Requiring all parameters or return 404

I am trying to require the user to input all parameters into the URL like this:
http://127.0.0.1:5000/api/movies/1?foo=a&bar=c
The browser displays;
1 a c
I would like to ensure that all parameters are included in the URL, and the other combinations of parameters would result in 404. How do I modify the code to do this?
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using MoviesAPI.Services;
namespace MoviesAPI.Controllers
{
public interface IActionConstraint : IActionConstraintMetadata
{
/// <summary>
/// The constraint order.
/// </summary>
/// <remarks>
/// Constraints are grouped into stages by the value of <see cref="Order"/>. See remarks on
/// <see cref="IActionConstraint"/>.
/// </remarks>
/// <summary>
/// Determines whether an action is a valid candidate for selection.
/// </summary>
/// <param name="context">The <see cref="ActionConstraintContext"/>.</param>
/// <returns>True if the action is valid for selection, otherwise false.</returns>
bool Accept(ActionConstraintContext context);
}
public class RequiredFromQueryActionConstraint : IActionConstraint
{
private readonly string _parameter;
public RequiredFromQueryActionConstraint(string parameter)
{
_parameter = parameter;
}
public bool Accept(ActionConstraintContext context)
{
if (!context.RouteContext.HttpContext.Request.Query.ContainsKey(_parameter))
{
return false;
}
return true;
}
}
public class RequiredFromQueryAttribute : FromQueryAttribute, IParameterModelConvention
{
public void Apply(ParameterModel parameter)
{
if (parameter.Action.Selectors != null && parameter.Action.Selectors.Any())
{
parameter.Action.Selectors.Last().ActionConstraints.Add(new RequiredFromQueryActionConstraint(parameter.BindingInfo?.BinderModelName ?? parameter.ParameterName));
}
}
}
[Route("api/[controller]")]
public class MoviesController : Controller
{
private MoviesDbContext _context;
public MoviesController(MoviesDbContext context)
{
_context = context;
}
public IActionResult GetMovies()
{
return Ok(_context.Movies);
}
[HttpGet("{id}")]
public string Get(int id, [RequiredFromQuery]string foo, [RequiredFromQuery]string bar)
{
return id + " " + foo + " " + bar;
}
}
}
IActionConstraint Interface is included in Microsoft.AspNetCore.Mvc.ActionConstraints.
Remove your interface code and add the Order property for the RequiredFromQueryActionConstraint
public class RequiredFromQueryActionConstraint : IActionConstraint
{
private readonly string _parameter;
public RequiredFromQueryActionConstraint(string parameter)
{
_parameter = parameter;
}
public int Order => 999;
public bool Accept(ActionConstraintContext context)
{
if (!context.RouteContext.HttpContext.Request.Query.ContainsKey(_parameter))
{
return false;
}
return true;
}
}
public class RequiredFromQueryAttribute : FromQueryAttribute, IParameterModelConvention
{
public void Apply(ParameterModel parameter)
{
if (parameter.Action.Selectors != null && parameter.Action.Selectors.Any())
{
parameter.Action.Selectors.Last().ActionConstraints.Add(new RequiredFromQueryActionConstraint(parameter.BindingInfo?.BinderModelName ?? parameter.ParameterName));
}
}
}
Refer to https://www.strathweb.com/2016/09/required-query-string-parameters-in-asp-net-core-mvc/

MVC 6 Identity ChangePassword for "SuperUser"

I need for "SuperUser" ability to change password of any user in identity system. I checked two solution.
1) add this one overloaded function to CustomUserManager for CRUD:
public async Task<IdentityResult> ChangePasswordAsync(TenantUser user, string newPassword)
{...}
Use original function with token parameter, but this function in controller not working and return invalid token:
string Token = await manager.GeneratePasswordResetTokenAsync(TenantUser);
var resultPasswordChange = await manager.ResetPasswordAsync(TenantUser, Token, model.TenantUsersPassword.Password);
Custom user manager: All PRIVATE functions and parameters has been already copied from orig UserManager to derived CustomUserManager. Resources for NotSupportedException are still not available... I'm not satisfacted with result...
Can you help me? What is better? Implement CustomUserManager or solve invalid token error? And please how to do?
Example what you need to copy for one more function (ChangePasswordAsync):
namespace Program.Models
{
public class TenantUserManager<TenantUser> : UserManager<TenantUser>, IDisposable where TenantUser : class
{
// protected const string ResetPasswordTokenPurpose = "ResetPassword";
// protected const string ConfirmEmailTokenPurpose = "EmailConfirmation";
private TimeSpan _defaultLockout = TimeSpan.Zero;
private bool _disposed;
private readonly HttpContext _context;
private CancellationToken CancellationToken => _context?.RequestAborted ?? CancellationToken.None;
/// <summary>
/// Constructs a new instance of <see cref="UserManager{TenantUser}"/>.
/// </summary>
/// <param name="store">The persistence store the manager will operate over.</param>
/// <param name="optionsAccessor">The accessor used to access the <see cref="IdentityOptions"/>.</param>
/// <param name="userValidators">A collection of <see cref="IUserValidator{TenantUser}"/> to validate users against.</param>
/// <param name="passwordValidators">A collection of <see cref="IPasswordValidator{TenantUser}"/> to validate passwords against.</param>
/// <param name="keyNormalizer">The <see cref="ILookupNormalizer"/> to use when generating index keys for users.</param>
/// <param name="errors">The <see cref="IdentityErrorDescriber"/> used to provider error messages.</param>
/// <param name="services">The <see cref="IServiceProvider"/> used to resolve services.</param>
public TenantUserManager(IUserStore<TenantUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TenantUser> passwordHasher, IEnumerable<IUserValidator<TenantUser>> userValidators,
IEnumerable<IPasswordValidator<TenantUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<TenantUser>> logger, IHttpContextAccessor contextAccessor)
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger, contextAccessor)
{
}
/// <summary>
/// Gets or sets the persistence store the manager operates over.
/// </summary>
/// <value>The persistence store the manager operates over.</value>
protected internal IUserStore<TenantUser> Store { get; set; }
/// <summary>
/// Gets the <see cref="ILogger"/> used to log messages from the manager.
/// </summary>
/// <value>
/// The <see cref="ILogger"/> used to log messages from the manager.
/// </value>
// protected internal virtual ILogger Logger { get; set; }
internal IPasswordHasher<TenantUser> PasswordHasher { get; set; }
internal IList<IUserValidator<TenantUser>> UserValidators { get; } = new List<IUserValidator<TenantUser>>();
internal IList<IPasswordValidator<TenantUser>> PasswordValidators { get; } = new List<IPasswordValidator<TenantUser>>();
internal ILookupNormalizer KeyNormalizer { get; set; }
internal IdentityErrorDescriber ErrorDescriber { get; set; }
internal IdentityOptions Options { get; set; }
public async Task<IdentityResult> ChangePasswordAsync(TenantUser user, string newPassword)
{
ThrowIfDisposed();
var passwordStore = GetPasswordStore();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var result = await UpdatePasswordHash(passwordStore, user, newPassword);
if (!result.Succeeded)
{
return result;
}
return await UpdateUserAsync(user);
// Logger.LogWarning(2, "Change password failed for user {userId}.", await GeTenantUserIdAsync(user));
// return IdentityResult.Failed(ErrorDescriber.PasswordMismatch());
}
private static string NewSecurityStamp()
{
return Guid.NewGuid().ToString();
}
private IUserSecurityStampStore<TenantUser> GetSecurityStore()
{
var cast = Store as IUserSecurityStampStore<TenantUser>;
if (cast == null)
{
throw new NotSupportedException("Resources.StoreNotIUserSecurityStampStore");
}
return cast;
}
// Update the security stamp if the store supports it
internal async Task UpdateSecurityStampInternal(TenantUser user)
{
if (SupportsUserSecurityStamp)
{
await GetSecurityStore().SetSecurityStampAsync(user, NewSecurityStamp(), CancellationToken);
}
}
internal async Task<IdentityResult> UpdatePasswordHash(IUserPasswordStore<TenantUser> passwordStore,
TenantUser user, string newPassword, bool validatePassword = true)
{
if (validatePassword)
{
var validate = await ValidatePasswordInternal(user, newPassword);
if (!validate.Succeeded)
{
return validate;
}
}
var hash = newPassword != null ? PasswordHasher.HashPassword(user, newPassword) : null;
await passwordStore.SetPasswordHashAsync(user, hash, CancellationToken);
await UpdateSecurityStampInternal(user);
return IdentityResult.Success;
}
private async Task<IdentityResult> ValidateUserInternal(TenantUser user)
{
var errors = new List<IdentityError>();
foreach (var v in UserValidators)
{
var result = await v.ValidateAsync(this, user);
if (!result.Succeeded)
{
errors.AddRange(result.Errors);
}
}
if (errors.Count > 0)
{
// Logger.LogWarning(13, "User {userId} validation failed: {errors}.", await GeTenantUserIdAsync(user), string.Join(";", errors.Select(e => e.Code)));
return IdentityResult.Failed(errors.ToArray());
}
return IdentityResult.Success;
}
private async Task<IdentityResult> ValidatePasswordInternal(TenantUser user, string password)
{
var errors = new List<IdentityError>();
foreach (var v in PasswordValidators)
{
var result = await v.ValidateAsync(this, user, password);
if (!result.Succeeded)
{
errors.AddRange(result.Errors);
}
}
if (errors.Count > 0)
{
// Logger.LogWarning(14, "User {userId} password validation failed: {errors}.", await GeTenantUserIdAsync(user), string.Join(";", errors.Select(e => e.Code)));
return IdentityResult.Failed(errors.ToArray());
}
return IdentityResult.Success;
}
private async Task<IdentityResult> UpdateUserAsync(TenantUser user)
{
var result = await ValidateUserInternal(user);
if (!result.Succeeded)
{
return result;
}
await UpdateNormalizedUserNameAsync(user);
await UpdateNormalizedEmailAsync(user);
return await Store.UpdateAsync(user, CancellationToken);
}
private IUserPasswordStore<TenantUser> GetPasswordStore()
{
var cast = Store as IUserPasswordStore<TenantUser>;
if (cast == null)
{
throw new NotSupportedException("Resources.StoreNotIUserPasswordStore"); //Resources are not awailable
}
return cast;
}
/// <summary>
/// Releases the unmanaged resources used by the role manager and optionally releases the managed resources.
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
protected override void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
Store.Dispose();
_disposed = true;
}
}
protected void ThrowIfDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(GetType().Name);
}
}
}

Circular Reference + IoC

I have this situation:
Web Project - calling a Business class using Unity 3 IoC. The Web Project doesn't see Business Project. It just references Contracts Project.
namespace Biblioteca.Web.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
var Autor = Inject.Resolve<IAutorBO>();
}
}
}
Business Project - Here I use the Unity 3 IoC to point to AutorDO class which is in the Data Project (see below). The Business Project doesn't see Data Project.
namespace Biblioteca.Data
{
public sealed partial class AutorBO : IAutorBO
{
#region Atributos
private IAutorDO AutorDO = Inject.Resolve<IAutorDO>();
#endregion
#region Métodos Interface
public IQueryable<DTOAutor> GetAll()
{
return AutorDO.GetAll();
}
public DTOAutor GetById(int id)
{
return AutorDO.GetById(id);
}
void IAutorBO.Insert(DTOAutor dto)
{
AutorDO.Insert(dto);
}
void IAutorBO.Delete(DTOAutor dto)
{
AutorDO.Delete(dto);
}
void IAutorBO.Update(DTOAutor dto)
{
AutorDO.Update(dto);
}
//IQueryable<DTOAutor> IAutorBO.SearchFor(Expression<Func<Autor, bool>> predicate)
//{
// return AutorDO.SearchFor(predicate);
//}
IQueryable<DTOAutor> IAutorBO.GetAll()
{
return AutorDO.GetAll();
}
DTOAutor IAutorBO.GetById(int id)
{
return AutorDO.GetById(id);
}
#endregion
#region Outros Métodos
#endregion
}
}
Data Access Project - Here is my Data Project.
namespace Biblioteca.Data
{
public sealed partial class AutorDO : IAutorDO
{
#region Atributos
Repository<Autor> repository = new Repository<Autor>();
#endregion
#region Implementações Interface
/// <summary>
/// Implementação do método de interface Insert
/// </summary>
/// <param name="dto"></param>
void IAutorDO.Insert(Transport.DTOAutor dto)
{
Autor entity = AssemblerAutor.ToEntity(dto);
repository.Insert(entity);
}
/// <summary>
/// Implementação do método de interface Delete
/// </summary>
/// <param name="dto"></param>
void IAutorDO.Delete(Transport.DTOAutor dto)
{
Autor entity = AssemblerAutor.ToEntity(dto);
repository.Delete(entity);
}
/// <summary>
/// Implementação do método de interface Update
/// </summary>
/// <param name="dto"></param>
void IAutorDO.Update(Transport.DTOAutor dto)
{
Autor entity = AssemblerAutor.ToEntity(dto);
repository.Update(entity);
}
/// <summary>
/// Implementação do método de interface SearchFor
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
//IQueryable<Transport.DTOAutor> IAutorDO.SearchFor(Expression<Func<Autor, bool>> predicate)
//{
// IQueryable<Autor> list = repository.SearchFor(predicate);
// IQueryable<Transport.DTOAutor> dtoList = (IQueryable<Transport.DTOAutor>)AssemblerAutor.ToDTOs(list);
// return dtoList;
//}
/// <summary>
/// Implementação do método de interface GetAll
/// </summary>
/// <returns></returns>
IQueryable<Transport.DTOAutor> IAutorDO.GetAll()
{
IQueryable<Autor> list = repository.GetAll();
IQueryable<Transport.DTOAutor> dtoList = (IQueryable<Transport.DTOAutor>)AssemblerAutor.ToDTOs(list);
return dtoList;
}
/// <summary>
/// Implementação do método de interface GetById
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Transport.DTOAutor IAutorDO.GetById(int id)
{
Autor entity = new Autor();
Transport.DTOAutor dto = new Transport.DTOAutor();
using (var ctx = new BibliotecaContext())
{
entity = repository.GetById(id);
dto = AssemblerAutor.ToDTO(entity);
}
return dto;
}
#endregion
}
}
Both Business and Data Projects references the Contracts Project which has all Unity 3 IoC Interfaces, used for implementing IoC. Below are the interfaces used to implement IoC:
namespace Biblioteca.Contracts
{
public interface IAutorBO
{
#region Métodos CRUD
void Insert(DTOAutor dto);
void Delete(DTOAutor dto);
void Update(DTOAutor dto);
//IQueryable<DTOAutor> SearchFor(Expression<Func<Autor, bool>> predicate);
IQueryable<DTOAutor> GetAll();
DTOAutor GetById(int id);
#endregion
}
}
namespace Biblioteca.Contracts
{
public interface IAutorDO
{
#region Métodos CRUD
void Insert(DTOAutor dto);
void Delete(DTOAutor dto);
void Update(DTOAutor dto);
//IQueryable<DTOAutor> SearchFor(Expression<Func<Autor, bool>> predicate);
IQueryable<DTOAutor> GetAll();
DTOAutor GetById(int id);
#endregion
}
}
To complement, I use a generic repository, as below:
namespace Biblioteca.Data
{
/// <summary>
/// Interface para classe genérica para métodos CRUD
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IRepository<T>
{
void Insert(T entity);
void Delete(T entity);
void Update(T entity);
IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
IQueryable<T> GetAll();
T GetById(int id);
}
}
namespace Biblioteca.Data
{
/// <summary>
/// Classe genérica para métodos CRUD da camada Data
/// </summary>
/// <typeparam name="T"></typeparam>
public class Repository<T> : IRepository<T> where T : class
{
#region Attributes
protected DbSet<T> dbset;
protected DbContext ctx;
#endregion
#region Constructor
public Repository()
{ }
public Repository(DbContext ctx)
{
this.ctx = ctx;
dbset = ctx.Set<T>();
}
#endregion
#region IRepository<T> Members
public void Insert(T entity)
{
if (dbset.Contains(entity))
{
Update(entity);
}
else
{
dbset.Add(entity);
}
}
public void Delete(T entity)
{
dbset.Remove(entity);
}
public void Update(T entity)
{
using (ctx)
{
ctx.Set<T>().Attach(entity);
ctx.SaveChanges();
}
}
public IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate)
{
return dbset.Where(predicate);
}
public IQueryable<T> GetAll()
{
return dbset;
}
public T GetById(int id)
{
return dbset.Find(id);
}
#endregion
}
}
Notice that I have a commented method in all classes. This Method can not be implemented cause it will cause a circular dependency.
I have the Data Project referencing Contract Project. But I can not use the method "SearchFor" cause it needs the Entity Autor which is in Data Project.
Notice that both Business and Data needs to see Entity classes, cause I have the same method signature.
I need some way to permit use the IoC the way it is, where Web not references Business and Business not references Data, and be able to create other methods where I can pass Entity as parameter.
Any suggestion ? I have already tried to create a third project and points to it but I can't make it works. Is it possible to use Reflection ? If possible, how ?
I will appreciate any suggestion.
If you have a circular dependency, it is a clue you should modify your architecture.
If you need to "have the Data Project referencing Contract Project", then Contract cannot reference Data to get the Entity. You say "Business and Data needs to see Entity classes", so why not keep your entity Autor in an Entities project.
Data
-> references Contract
-> references Entities
Contract
-> references Entities
Or as an alternative, define your entities in the Contract project instead of Data.

WCF services, loading data from database

I have some problem with WCF services in asp.net mvc application.
Help me please!
When I run my project some data for some entities are loading from database, but some data are not loading(Internal server error).
Code and description of exceptions:
EntityTypeController:
public HttpResponseMessage GetAll()
{
//for debug
var t = EntityTypeService.GetAll();
//some exception here!
/*
The request channel timed out while waiting for a reply after 00:00:59.9979999.
Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding.
The time allotted to this operation may have been a portion of a longer timeout.
*/
//SendTimeout is 00:30:00 for all services.
or
/*The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.*/
or
/*An error occurred while receiving the HTTP response to http://localhost:18822/Services/Department.svc.
This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an
HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.*/
return CreateResponse<IEnumerable<EntityType>>(EntityTypeService.GetAll);
}
EntityTypeService:
public class EntityTypeService : BaseService<Base.Entities.EntityType>, IEntityTypeService
{
public IQueryable<Base.Entities.EntityType> GetAll()
{
var t = Repository.Get();
return t;
}
}
Repository:
public class Repository<TEntity>: IRepository<TEntity> where TEntity: BaseEntity
{
[Inject]
public IDataContext Context { get; set; }
[Inject]
public IDatabase DataSource { get; set; }
/// <summary>
/// Get entities from repository
/// </summary>
/// <param name="filter">Filter</param>
/// <param name="orderBy">Order by property</param>
/// <param name="includeProperties"></param>
/// <returns></returns>
public virtual IQueryable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
var query = Context.Set<TEntity>().AsQueryable();
// Apply filter
filter.Do((s) => {
query = query.Where(filter);
});
// Apply includes
foreach (var includeProperty in includeProperties.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
// Apply order by if need
var result = orderBy
.With(x => x(query))
.Return(x => x, query);
return result;
}
/// <summary>
/// Find entity by key
/// </summary>
/// <param name="id">Identificator</param>
/// <returns>Entity</returns>
public virtual TEntity GetById(object id)
{
//throw new NotImplementedException();
return Context.Set<TEntity>().Find(id);
}
/// <summary>
/// Add new entity to repository
/// </summary>
/// <param name="entity">New entity</param>
public virtual void Insert(TEntity entity)
{
AttachIsNotAttached(entity);
Context.Set<TEntity>().Add(entity);
Context.SaveChanges();
}
/// <summary>
/// Updated entity in repositoy
/// </summary>
/// <param name="entity">Entity</param>
public virtual void Update(TEntity entity)
{
AttachIsNotAttached(entity);
Context.Entry(entity).State = EntityState.Modified;
Context.SaveChanges();
}
/// <summary>
/// Remove entity from rpository
/// </summary>
/// <param name="entity">Entity</param>
public virtual void Delete(TEntity entity)
{
AttachIsNotAttached(entity);
Context.Set<TEntity>().Remove(entity);
Context.Entry(entity).State = EntityState.Deleted;
Context.SaveChanges();
}
/// <summary>
/// Return models error
/// </summary>
/// <returns></returns>
public IEnumerable<object> GetValidationModelErrors()
{
return Context.GetValidationErrors();
}
/// <summary>
/// Attach entity
/// </summary>
/// <param name="entity"></param>
protected void AttachIsNotAttached(TEntity entity)
{
if (Context.Entry(entity).State == EntityState.Detached)
{
var attached = Context.Set<TEntity>().Local.Where(x => x.Id == entity.Id).FirstOrDefault();
attached.Do((s) => {
Context.Entry(s).State = EntityState.Detached;
});
Context.Set<TEntity>().Attach(entity);
}
}
}
By default the wcf config has many limitations like the max size of array, and the exception doesnt exactly what happens,maybe in your case it's due to the default wcf config, I advice you to use svcTraceViewer, it will help you a lot to understand what happen exactly with an explicit messages.

Resources