Entity Framework 5 + Ninject: AutoDetectChanges issue with foreign keys - foreign-keys

I'm trying to use the Onion Pattern with Generic Repositories + Unit of work + Entity Framework 5 + Ninject with Asp.net MVC4 but I'm having a problem with EF "DetectChanges" feature and I don't understand why I need to set it to "false".
Could you please help me?
My solution is to add the following line to the constructor of FindingBugContext.cs file:
Configuration.AutoDetectChangesEnabled = false;
In the commented lines of the following code, I'll explain more clearly my isssue.
It's a very simple (and maybe stupid) code reproducing the issue I don't understand and I didn't include the code for all interfaces because I think it's pretty simple to figure it out.
This is my service class, "RobotService.cs":
public class RobotService : IRobotService
{
private readonly IRepository<Body> _repoBody;
private readonly IRepository<BodyPart> _repoBodyPart;
private readonly IRepository<Robot> _repoRobot;
private readonly IUnitOfWork _unitOfWork;
public RobotService(
IRepository<Body> repoBody,
IRepository<BodyPart> repoBodyPart,
IRepository<Robot> repoRobot,
IUnitOfWork unitOfWork)
{
_repoBody = repoBody;
_repoBodyPart = repoBodyPart;
_repoRobot = repoRobot;
_unitOfWork = unitOfWork;
}
public Robot Get(int id)
{
Robot robot = new Robot();
robot = _repoRobot.Get(id);
if (robot != null)
{
Body body = _repoBody.Get(robot.BodyId);
/* FROM NOW ON:
* robot.BodyId = 0 --> instead of 1: WHY???
* robot.Name = "Robby1"
*/
if (body != null)
{
BodyPart head = new BodyPart();
head = _repoBodyPart.Get(body.HeadId);
body.Head = head;
/* FROM NOW ON:
* body.BodyId = 0 --> instead of 1: WHY???
* body.HeadId = 0 --> instead of 1: WHY???
* body.LeftArmId = 0 --> instead of 2: WHY???
* body.RightArmId = 0 --> instead of 3: WHY???
* body.BodyName = "Body1" --> doesn't change
*/
BodyPart leftArm = new BodyPart();
leftArm = _repoBodyPart.Get(body.LeftArmId);
body.LeftArm = leftArm;
BodyPart rightArm = new BodyPart();
rightArm = _repoBodyPart.Get(body.RightArmId);
body.RightArm = rightArm;
robot.Body = body;
}
}
return robot;
}
This is my custom code inside NinjectWebCommon.cs file after installation through NuGet package "Ninject.MVC3":
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(typeof(IRepository<>)).To(typeof(RepositoryBase<>)).InRequestScope();
kernel.Bind<IDbContextFactory>().To<DbContextFactory>().InRequestScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
kernel.Bind<IRobotService>().To<RobotService>();
}
This is my DbContext class "FindingBugContext.cs":
public class FindingBugContext : DbContext
{
public FindingBugContext()
: base("FindingBugContext")
{
//Configuration.AutoDetectChangesEnabled = false; //This is the solution
}
public virtual void Commit()
{
base.SaveChanges();
}
private IDbSet<Robot> _robots;
private IDbSet<Body> _bodies;
private IDbSet<BodyPart> _bodyParts;
public virtual IDbSet<T> DbSet<T>() where T : class
{
return Set<T>();
}
public IDbSet<Robot> Robots
{
get { return _robots ?? (_robots = DbSet<Robot>()); }
}
public IDbSet<Body> Bodies
{
get { return _bodies ?? (_bodies = DbSet<Body>()); }
}
public IDbSet<BodyPart> BodyParts
{
get { return _bodyParts ?? (_bodyParts = DbSet<BodyPart>()); }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new DropCreateFindingBugWithSeedData());
modelBuilder.Configurations.Add(new RobotConfiguration());
modelBuilder.Configurations.Add(new BodyConfiguration());
modelBuilder.Configurations.Add(new BodyPartConfiguration());
}
public class DropCreateFindingBugWithSeedData : DropCreateDatabaseAlways<FindingBugContext>
{
protected override void Seed(FindingBugContext context)
{
BodyPart head = new BodyPart() { Type = PartType.Head, PartName = "Head" };
BodyPart leftArm = new BodyPart() { Type = PartType.LeftArm, PartName = "LeftArm" };
BodyPart rightArm = new BodyPart() { Type = PartType.RightArm, PartName = "RightArm" };
Body body = new Body() { BodyName = "Body1", Head = head, HeadId = 1, LeftArm = leftArm, LeftArmId = 2, RightArm = rightArm, RightArmId = 3 };
Robot robot = new Robot() { Name = "Robby1", BodyId = 1, Body = body };
context.Robots.Add(robot);
}
}
public class RobotConfiguration : EntityTypeConfiguration<Robot>
{
public RobotConfiguration()
{
ToTable("Robots");
HasKey(r => r.RobotId)
.Property(r => r.RobotId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasRequired(r => r.Body)
.WithMany()
.HasForeignKey(r => r.BodyId);
}
}
public class BodyConfiguration : EntityTypeConfiguration<Body>
{
public BodyConfiguration()
{
ToTable("Bodies");
HasKey(b => b.BodyId)
.Property(b => b.BodyId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasRequired(b => b.Head)
.WithMany()
.HasForeignKey(b => b.HeadId)
.WillCascadeOnDelete(false);
HasRequired(b => b.LeftArm)
.WithMany()
.HasForeignKey(b => b.LeftArmId)
.WillCascadeOnDelete(false);
HasRequired(b => b.RightArm)
.WithMany()
.HasForeignKey(b => b.RightArmId)
.WillCascadeOnDelete(false);
}
}
public class BodyPartConfiguration : EntityTypeConfiguration<BodyPart>
{
public BodyPartConfiguration()
{
ToTable("BodyParts");
HasKey(b => b.BodyPartId)
.Property(b => b.BodyPartId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
}
These are my Entities:
public class Robot
{
public Robot() { Body = new Body(); }
public int RobotId { get; set; }
public string Name { get; set; }
public int BodyId { get; set; }
public Body Body { get; set; }
}
public class Body
{
public Body()
{
Head = new BodyPart();
LeftArm = new BodyPart();
RightArm = new BodyPart();
}
public int BodyId { get; set; }
public string BodyName { get; set; }
public int HeadId { get; set; }
public BodyPart Head { get; set; }
public int LeftArmId { get; set; }
public BodyPart LeftArm { get; set; }
public int RightArmId { get; set; }
public BodyPart RightArm { get; set; }
}
public class BodyPart
{
public int BodyPartId { get; set; }
public PartType Type { get; set; }
public string PartName { get; set; }
}
public enum PartType
{
Head,
LeftArm,
RightArm
}
This is the Unit of Work code:
public class UnitOfWork : IUnitOfWork
{
private readonly IDbContextFactory _dbContextFactory;
private FindingBugContext _context;
public UnitOfWork(IDbContextFactory dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
protected FindingBugContext FindingBugContext
{
get { return _context ?? (_context = _dbContextFactory.Get()); }
}
public void Commit()
{
FindingBugContext.Commit();
}
}
This is the Generic Repository code:
public class RepositoryBase<T> : IRepository<T> where T : class
{
private FindingBugContext _context;
private readonly IDbSet<T> _dbSet;
public RepositoryBase(IDbContextFactory dbContextFactory)
{
DbContextFactory = dbContextFactory;
_dbSet = FindingBugContext.Set<T>();
}
public IDbContextFactory DbContextFactory
{
get;
private set;
}
public FindingBugContext FindingBugContext
{
get { return _context ?? (_context = DbContextFactory.Get()); }
}
//Read
public T Get(int id)
{
return _dbSet.Find(id);
}
}
This is my ContextFactory code:
public class DbContextFactory : Disposable, IDbContextFactory
{
private FindingBugContext _context;
public FindingBugContext Get()
{
if (_context == null)
{
_context = new FindingBugContext();
return _context;
}
else
{
return _context;
}
}
public void Dispose()
{
if (_context != null)
{
_context.Dispose();
}
}
}

Related

Converted List That Got From Reflection

I get a list using reflection and I want to fill that list with data this way :
public class SearchCriteria
{
public int SearchValue { get; set; }
public string SearchField { get; set; }
}
public class intListRequest
{
public List<SearchCriteria> SearchList { get; set; }
}
private static void ApplySearchList(intListRequest request)
{
Type type = typeof(intListRequest);
var propers = type.GetProperties();
var propsResult = propers.Where(a => a.Name == "intList");
var prop = propsResult.FirstOrDefault();
if (prop.PropertyType == typeof(List<int>))
{
List<int> newprop = prop.CastTo<List<int>>(); //**error here**//
newprop.Add(SearchValue1);
newprop.Add(SearchValue2);
newprop.Add(SearchValue3);
}
}
my problem Is with the line that I showed, how can I convert that to an int List?

Perform xUnit Moq test to create record and save it to DbContext

I am writing test for Web API application written in .NET CORE 3.1. I am using xUnit, AutoFixture & Moq for testing. I have a class that creates a new school instance in the database using Entity Framework/ DbContext. My question is how to mock dbContext & save changes, further my School DataModel has one: many relationships with SchoolBranch DataModel. I have followed this tutorial https://learn.microsoft.com/en-us/ef/ef6/fundamentals/testing/mocking
Error
Message:
Moq.MockException :
Expected invocation on the mock once, but was 0 times: m => m.Add<School>(It.IsAny<School>())
Performed invocations:
Mock<SchoolDbContext:1> (m):
No invocations performed.
Stack Trace:
Mock.Verify(Mock mock, LambdaExpression expression, Times times, String failMessage)
Mock`1.Verify[TResult](Expression`1 expression, Times times)
CreateSchoolCommandTest.ExecuteMethod_ShouldReturnNewGuidId_IfSuccess() line 50
School
public class School
{
public School()
{
this.SchoolBranches = new HashSet<SchoolBranch>();
}
public Guid SchoolID { get; set; }
public string Name { get; set; }
public ICollection<SchoolBranch> SchoolBranches { get; set; }
}
SchoolBranch
public class SchoolBranch
{
public SchoolBranch()
{
}
public Guid SchoolBranchID { get; set; }
public Guid SchoolID { get; set; }
public string Address { get; set; }
public int PhoneNumber { get; set; }
public School School { get; set; }
}
CreateSchool Class
public class CreateSchool : BaseCommand<Guid>, ICreateSchool
{
public SchoolDto SchoolDtos { get; set; }
public CreateSchool(IAppAmbientState appAmbient) : base(appAmbient) { }
public override Guid Execute()
{
try
{
var schoolId = Guid.NewGuid();
List<SchoolBranch> schoolBranches = new List<SchoolBranch>();
foreach(var item in SchoolDtos.SchoolBranchDtos)
{
schoolBranches.Add(new SchoolBranch()
{
SchoolBranchID = Guid.NewGuid(),
SchoolID = schoolId,
Address = item.Address,
PhoneNumber = item.PhoneNumber
});
}
var school = new School()
{
SchoolID = schoolId,
Name = SchoolDtos.Name,
SchoolBranches = schoolBranches
};
schoolDbContext.Schools.Add(school);
schoolDbContext.SaveChanges();
return school.SchoolID;
}
catch(Exception exp)
{
appAmbientState.Logger.LogError(exp);
throw;
}
}
}
Test Class
public class CreateSchoolCommandTest
{
private readonly ICreateSchool sut;
private readonly Mock<IAppAmbientState> appAmbientState = new Mock<IAppAmbientState>();
[Fact]
public void ExecuteMethod_ShouldReturnNewGuidId_IfSuccess()
{
//Arrange
var fixture = new Fixture();
var schoolDtoMock = fixture.Create<SchoolDto>();
var schoolDbSetMock = new Mock<DbSet<School>>();
var schoolBranchDbSetMock = new Mock<DbSet<SchoolBranch>>();
var schoolDbContextMock = new Mock<SchoolDbContext>();
//schoolDbSetMock.Setup(x => x.Add(It.IsAny<School>())).Returns((School s) => s); // this also did not work
schoolDbContextMock.Setup(m => m.Schools).Returns(schoolDbSetMock.Object);
//Act
sut.SchoolDtos = schoolDtoMock;
var actualDataResult = sut.Execute();
// Assert
Assert.IsType<Guid>(actualDataResult);
schoolDbContextMock.Verify(m => m.Add(It.IsAny<School>()), Times.Once());
schoolDbContextMock.Verify(m => m.SaveChanges(), Times.Once());
}
BaseCommand (DbContext is created here)
public abstract class BaseCommand<T>
{
protected SchoolDbContext schoolDbContext;
protected IAppAmbientState appAmbientState { get; }
public BaseCommand(IAppAmbientState ambientState)
{
this.schoolDbContext = new SchoolDbContext();
this.appAmbientState = ambientState;
}
public abstract T Execute();
}
For fix Error
You made just a little mistake. Insted of
schoolDbContextMock.Verify(m => m.Add(It.IsAny<School>()), Times.Once());
schoolDbContextMock.Verify(m => m.SaveChanges(), Times.Once());
You should have
schoolDbSetMock.Verify(m => m.Add(It.IsAny<School>()), Times.Once());
schoolDbContextMock.Verify(m => m.SaveChanges(), Times.Once());
Because you use method Add() on schoolDbContext.Schools not on schoolDbContext
For injecting dbContext
Your BaseCoommand class constructor should look like this:
public BaseCommand(IAppAmbientState ambientState, SchoolDbContext schoolDbContext)
{
this.schoolDbContext = schoolDbContext;
this.appAmbientState = ambientState;
}
Your CreateSchool class constructor:
public CreateSchool(IAppAmbientState appAmbient, SchoolDbContext schoolDbContext) : base(appAmbient, schoolDbContext) { }
And next in test you should initialize CreateSchool in test like this:
var sut = new CreateSchool(ambientState, schoolDbContextMock.Object);
And it will work

Unable to resolve service for type 'Api.Repositories.UnitOfWork' while attempting to activate 'Api.ServicesBusiness.EquipoServices'

I want to make a webapi and I'm trying to do it through the services way, I have a repository generic and another 2 repository and a unit of work, apparently everything goes fine, but when I run and test the webapi from postman I got that error:
InvalidOperationException: Unable to resolve service for type 'Api.Repository.Repositories.UnitOfWork' while attempting to activate 'Api.ServicesBusiness.Implementacion.EquipoServices'.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)
Here is the my dbcontect:
public class AppDbContext : DbContext
{
public AppDbContext()
{
}
public AppDbContext(DbContextOptions<AppDbContext> option) :base(option)
{
}
public DbSet<Equipo> Equipos { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\Express;Database=SoftballLeague;Trusted_Connection=True");
}
}
}
Here is the interface of my generic repository:
public interface IGenericRepository<T> where T : class
{
Task<T> AddAsyn(T t);
Task<T> UpdateAsyn(T t, object key);
}
Here is the implementation of my generic repository:
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private readonly AppDbContext _context;
private readonly DbSet<T> _dbSet;
public GenericRepository(AppDbContext context)
{
_context = context;
_dbSet = _context.Set<T>();
}
public virtual async Task<T> AddAsyn(T t)
{
_dbSet.Add(t);
await _context.SaveChangesAsync();
return t;
}
public virtual async Task<T> UpdateAsyn(T t, object key)
{
if (t == null)
return null;
T exist = await _dbSet.FindAsync(key);
if (exist != null)
{
_context.Entry(exist).CurrentValues.SetValues(t);
await _context.SaveChangesAsync();
}
return exist;
}
}
Here is the interface of my equipo repository:
public interface IEquipoRepository:IGenericRepository<Team>
{
int GetAverageTeam(string name);
int GetTeamHit(string name);
}
Here is the implementation of my equipo repository:
public class EquipoRepository : GenericRepository<Team>, IEquipoRepository
{
private readonly AppDbContext dbContext;
public EquipoRepository(AppDbContext context) : base(context)
{
this.dbContext = context;
}
public int GetAverageTeam(string name)
{
int teamAverage = 0;
var resultAverage = this.dbContext.Equipos
//.SelectMany(bItem => bItem.)
.Where(equipo=>equipo.Nombre==name)
.SelectMany(equipo => equipo.jugadores)
.Average(jugador => jugador.Average);
if (resultAverage.HasValue)
teamAverage =Convert.ToInt32(Math.Round(resultAverage.Value));
return teamAverage;
}
public int GetTeamHit(string name)
{
int resultTotal = 0;
var result = this.dbContext.Equipos
//.SelectMany(bItem => bItem.)
.Where(equipo => equipo.Nombre == name)
.SelectMany(equipo => equipo.jugadores)
.Sum(jugador => jugador.Cant_Hits_Conectados);
if (result.HasValue)
resultTotal = result.Value;
return resultTotal;
}
}
Here is the interface of my unit of work:
public interface IUnitOfWork:IDisposable
{
Task Commit();
}
Here is the implementation of my unit of work:
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _DbContext;
private EquipoRepository equipoRepository ;
public UnitOfWork(AppDbContext dbContext)
{
this._DbContext = dbContext;
this.equipoRepository = new EquipoRepository(this._DbContext);
}
public EquipoRepository GetEquipoRepository{
get {
if(this.equipoRepository==null)
this.equipoRepository= new EquipoRepository(this._DbContext);
return this.equipoRepository;
}
}
public async Task Commit()
{
await this._DbContext.SaveChangesAsync();
}
public void Dispose()
{
this._DbContext.Dispose();
}
}
Here is the implementation of services interfaces IEquipoServices:
public interface IEquipoServices
{
ICollection<EstadisticaEquipoModel>AveragePorEquipo(string name);
int Total2bleConectados(string name);
}
Here is the implementation of services EquipoServices which is the one who throws the error:
public class EquipoServices : IEquipoServices
{
private readonly UnitOfWork unit;
public EquipoServices(UnitOfWork unitOfWorkFactory)
{
this.unit = unitOfWorkFactory;
}
public ICollection<EstadisticaEquipoModel> AveragePorEquipo(string name)
{
var equipoAverage= this.unit.GetEquipoRepository.GetAverageEquipo(name);
return equipoAverage;
}
public int AveragePorEquipo(string name)
{
var result = this.unit.GetEquipoRepository.GetEquipoTotal2bleConectados(name);
return result;
}
}
This is the controller, here I am just running the ListadoEquipos() method:
[Route("api/[controller]")]
public class EquipoController : ControllerBase
{
private readonly IEquipoServices equipoService;
private readonly IMapper _mapper;
public EquipoController(IEquipoServices eqService, IMapper mapper)
{
this.equipoService = eqService;
this._mapper = mapper;
}
[HttpGet("list")]
public IEnumerable<string> ListadoEquipos()
{
return new string[] { "value1", "value2" };
}
}
This is the configuration in the startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options=>options.UseSqlServer(Configuration.GetConnectionString("ConnectionString")));
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
services.AddSingleton<IEquipoServices, EquipoServices>();
//services.AddScoped<IJu, JugadorService>();
services.AddAutoMapper(typeof(Startup));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
You registered IUnitOfWork, but you're injecting UnitOfWork. The service collection doesn't know how to inject UnitOfWork directly.
Long and short, inject IUnitOfWork instead:
private readonly IUnitOfWork unit;
public EquipoServices(IUnitOfWork unitOfWorkFactory)

New kendo sheduler events don't call controller methods

I'm trying to add a new scheduler event to database. It's added to the scheduler datasource and its visible in scheduler, but isn't call controller Create method.
Edit or delete newly added event also don't call controller methods, but change datasource.
Already exists events work well.
Model:
public class ResourceSchedulerModel : ISchedulerEvent
{
public string Title { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
public string Description { get; set; }
public bool IsAllDay { get; set; }
public string RecurrenceRule { get; set; }
public string RecurrenceException { get; set; }
public string EndTimezone { get; set; }
public string StartTimezone { get; set; }
public int BTS_Id { get; set; }
public ResourceSchedulerModel() { }
public ResourceSchedulerModel(BusyTimeSlot bts)
{
BTS_Id = bts.BTS_Id;
Start = bts.BTS_From;
End = bts.BTS_To;
Title = bts.BTS_Name;
Description = bts.BTS_Description;
ResId = bts.BTS_RES_Id;
}
}
Controller methods:
public virtual JsonResult Read([DataSourceRequest] DataSourceRequest request)
{
EntityWrapper ew = new EntityWrapper();
List<BusyTimeSlot> btss = ew.GetAllBusyTimeSlots();
List<ResourceSchedulerModel> sm = new List<ResourceSchedulerModel>();
foreach (BusyTimeSlot b in btss)
sm.Add(new ResourceSchedulerModel(b));
return Json(sm.ToDataSourceResult(request));
}
public virtual JsonResult Destroy([DataSourceRequest] DataSourceRequest request, ResourceSchedulerModel task)
{
if (ModelState.IsValid)
{
// delete
}
return Json(new[] { task }.ToDataSourceResult(request, ModelState));
}
public virtual JsonResult Create([DataSourceRequest] DataSourceRequest request, ResourceSchedulerModel task)
{
if (ModelState.IsValid)
{
//add
}
return Json(new[] { task }.ToDataSourceResult(request, ModelState));
}
public virtual JsonResult Update([DataSourceRequest] DataSourceRequest request, ResourceSchedulerModel task)
{
if (ModelState.IsValid)
{
// edit
}
return Json(new[] { task }.ToDataSourceResult(request, ModelState));
}
View:
#(Html.Kendo().Scheduler<SchedulerTry.Models.ResourceSchedulerModel>()
.Name("scheduler")
.Date(new DateTime(2014, 10, 11))
.MinorTickCount(1)
.Views(views =>
{
views.DayView();
views.WeekView(weekView => weekView.Selected(true));
views.MonthView();
views.AgendaView();
})
.DataSource(d => d
.Model(m => {
m.Id(f => f.BTS_Id);
m.Field(f => f.Title).DefaultValue("No title");
})
.Read("Read", "Resource")
.Create("Create", "Resource")
.Destroy("Destroy", "Resource")
.Update("Update", "Resource")
)
)
In addition, when I try close or cancel the edit window of new event I get an error
Uncaught TypeError: Cannot read property 'BTS_Id' of undefined kendo.all.min.js:11
Try updating the BTS_Id as below intialization as below:
public int bTS_Id;
public string BTS_Id
{
get
{
return bTS_Id;
}
set
{
bTS_Id = value;
}
}
My bad, I have another Create method in controller.

Silverlight & RIA Services: Managing Users

I want to manage users and Roles in the cliente side, but i cannot find the way to accomplish this. Links or code will be very appreciated.
Sorry for this abandoned question, i have solved this issue many days ago now, and i fill i should post the answer here because i couldnt find a complete answer in the web and this can help some soul in distress over there. Except for a link that i cannot remember right now but,my apologise to the blog owner for not remember even his name, however, here is the full history:
First create a class to wrap MembershipUser and another one to wrap MembsershipRole:
public class MembershipServiceUser
{
public string Comment { get; set; }
[Editable(false)]
public DateTime CreationDate { get; set; }
[Key]
[Editable(false, AllowInitialValue = true)]
public string Email { get; set; }
public bool IsApproved { get; set; }
[Editable(false)]
public bool IsLockedOut { get; set; }
[Editable(false)]
public bool IsOnline { get; set; }
public DateTime LastActivityDate { get; set; }
[Editable(false)]
public DateTime LastLockoutDate { get; set; }
public DateTime LastLoginDate { get; set; }
[Editable(false)]
public DateTime LastPasswordChangedDate { get; set; }
[Editable(false)]
public string PasswordQuestion { get; set; }
[Key]
[Editable(false, AllowInitialValue = true)]
public string UserName { get; set; }
public MembershipServiceUser() { }
public MembershipServiceUser(MembershipUser user)
{
this.FromMembershipUser(user);
}
public void FromMembershipUser(MembershipUser user)
{
this.Comment = user.Comment;
this.CreationDate = user.CreationDate;
this.Email = user.Email;
this.IsApproved = user.IsApproved;
this.IsLockedOut = user.IsLockedOut;
this.IsOnline = user.IsOnline;
this.LastActivityDate = user.LastActivityDate;
this.LastLockoutDate = user.LastLockoutDate;
this.LastLoginDate = user.LastLoginDate;
this.LastPasswordChangedDate = user.LastPasswordChangedDate;
this.PasswordQuestion = user.PasswordQuestion;
this.UserName = user.UserName;
}
public MembershipUser ToMembershipUser()
{
MembershipUser user = Membership.GetUser(this.UserName);
if (user.Comment != this.Comment) user.Comment = this.Comment;
if (user.IsApproved != this.IsApproved) user.IsApproved = this.IsApproved;
if (user.LastActivityDate != this.LastActivityDate) user.LastActivityDate = this.LastActivityDate;
if (user.LastLoginDate != this.LastLoginDate) user.LastLoginDate = this.LastLoginDate;
return user;
}
}
//Roles
public class MembershipServiceRole {
public MembershipServiceRole() { }
public MembershipServiceRole(string rolename) {
RoleName = rolename;
}
[Key]
[Editable(true, AllowInitialValue = true)]
public string RoleName { get; set; }
}
Second, create a class derived from DomainService to manipulate users and roles wrappers:
[EnableClientAccess(RequiresSecureEndpoint = false /* This should be set to true before the application is deployed */)]
public class MembershipService : DomainService
{
protected override void OnError(DomainServiceErrorInfo errorInfo)
{
TimeoutHelper.HandleAuthenticationTimeout(errorInfo, this.ServiceContext.User);
}
[RequiresRole("Administrator")]
public IEnumerable<MembershipServiceUser> GetUsers()
{
return Membership.GetAllUsers().Cast<MembershipUser>().Select(u => new MembershipServiceUser(u));
}
[RequiresRole("Administrator")]
public IEnumerable<MembershipServiceUser> GetUsersByEmail(string email)
{
return Membership.FindUsersByEmail(email).Cast<MembershipUser>().Select(u => new MembershipServiceUser(u));
}
[RequiresRole("Administrator")]
public MembershipServiceUser GetUsersByName(string userName)
{
MembershipServiceUser retVal = null;
retVal = Membership.FindUsersByName(userName)
.Cast<MembershipUser>()
.Select(u => new MembershipServiceUser(u))
.FirstOrDefault();
return retVal;
}
[Invoke(HasSideEffects = true)]
public void CreateUser(MembershipServiceUser user, string password)
{
if (string.IsNullOrEmpty(user.Email)) {
user.Email = "cambiar#dominio.com";
}
Membership.CreateUser(user.UserName, password, user.Email);
}
[RequiresRole("Administrator")]
public void DeleteUser(MembershipServiceUser user)
{
Membership.DeleteUser(user.UserName);
}
[RequiresRole("Administrator")]
public void UpdateUser(MembershipServiceUser user)
{
Membership.UpdateUser(user.ToMembershipUser());
}
[RequiresRole("Administrator")]
[Update(UsingCustomMethod = true)]
public void ChangePassword(MembershipServiceUser user, string newPassword)
{
MembershipUser u = user.ToMembershipUser();
u.ChangePassword(u.ResetPassword(), newPassword);
}
[RequiresRole("Administrator")]
public void ResetPassword(MembershipServiceUser user)
{
user.ToMembershipUser().ResetPassword();
}
[RequiresRole("Administrator")]
public void UnlockUser(MembershipServiceUser user)
{
user.ToMembershipUser().UnlockUser();
}
#region Roles
[RequiresRole("Administrator")]
public IEnumerable<MembershipServiceRole> GetRoles() {
return Roles.GetAllRoles().Cast<string>().Select(r => new MembershipServiceRole(r));
}
[RequiresRole("Administrator")]
public IEnumerable<MembershipServiceRole> GetRolesForUser(string userName) {
return Roles.GetRolesForUser(userName).Cast<string>().Select(r => new MembershipServiceRole(r));
}
[RequiresRole("Administrator")]
public void CreateRole(MembershipServiceRole role) {
Roles.CreateRole(role.RoleName);
}
[RequiresRole("Administrator")]
public void DeleteRole(MembershipServiceRole role) {
Roles.DeleteRole(role.RoleName);
}
[RequiresRole("Administrator")][Invoke]
public void AddUserToRole(string userName, string roleName) {
if (!Roles.IsUserInRole(userName,roleName))
Roles.AddUserToRole(userName, roleName);
}
[RequiresRole("Administrator")]
[Invoke]
public void RemoveUserFromRole(string userName, string roleName) {
if (Roles.IsUserInRole(userName, roleName))
Roles.RemoveUserFromRole(userName, roleName);
}
#endregion //Roles
}
Third: Use the service the same way you do for your domains clases
Cheers!!!