...
 
Commits (42)
......@@ -26,3 +26,4 @@
/src/Tests/Test.Breeze.Services/obj
/src/CMS/bin
/src/CMS/obj
/tmp
......@@ -12,10 +12,11 @@
<ItemGroup>
<BuildProject Include="src\BL.sln" />
<!--
<BreezeLibCMSDLLs Include="build\$(Configuration)\Breeze.CMS.dll" />
<BreezeLibAzureDLLs Include="build\$(Configuration)\Breeze.Media.Services.Azure.dll" />
<BreezeLibDLLs Include="build\$(Configuration)\Breeze.*.dll" Exclude="@(BreezeLibAzureDLLs)" />
<BreezeLibDLLs Include="build\$(Configuration)\Breeze.*.dll" Exclude="@(BreezeLibAzureDLLs);@(BreezeLibCMSDLLs)" />
-->
</ItemGroup>
<Target Name="Build" DependsOnTargets="RestorePackages">
......@@ -40,7 +41,16 @@
</Target>
<Target Name="nuget-pack" DependsOnTargets="Build;">
<MakeDir Directories="build\nuget\BreezeLib;build\nuget\BreezeLib.Azure;build\buget\BreezeLib.CMS" />
<MakeDir Directories="build\nuget\BreezeLib;build\nuget\BreezeLib.Azure;build\nuget\BreezeLib.CMS" />
<CreateItem Include="build\$(Configuration)\Breeze.CMS.dll">
<Output TaskParameter="Include" ItemName="BreezeLibCMSDLLs"/>
</CreateItem>
<CreateItem Include="build\$(Configuration)\Breeze.Media.Services.Azure.dll">
<Output TaskParameter="Include" ItemName="BreezeLibAzureDLLs"/>
</CreateItem>
<CreateItem Include="build\$(Configuration)\Breeze.*.dll" Exclude="@(BreezeLibAzureDLLs);@(BreezeLibCMSDLLs)">
<Output TaskParameter="Include" ItemName="BreezeLibDLLs"/>
</CreateItem>
<Copy SourceFiles="@(BreezeLibDLLs)" DestinationFolder="$(BuildRoot)\nuget\BreezeLib\lib\net45" />
<Copy SourceFiles="@(BreezeLibAzureDLLs)" DestinationFolder="$(BuildRoot)\nuget\BreezeLib.Azure\lib\net45" />
......
......@@ -5,7 +5,7 @@
<PropertyGroup>
<ContribPath>..\..\..</ContribPath>
<productVersion>7.0.6</productVersion>
<productVersion>7.0.7</productVersion>
</PropertyGroup>
<Target Name="Settings">
......
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Settings">
<PropertyGroup>
<xUnitDir>C:\Bin\xunit</xUnitDir>
</PropertyGroup>
......

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "General", "General", "{2F3BE202-9AA7-46EF-A201-B4FF4F76F054}"
EndProject
......@@ -25,13 +25,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Breeze.Diagnostics", "Gener
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Media.Services.Azure", "Media\Media.Services.Azure\Media.Services.Azure.csproj", "{84F8B9D1-E15F-487E-B6B2-54ED1FA8A3F7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{30587DF6-14BD-4F3C-8478-3DE559964774}"
ProjectSection(SolutionItems) = preProject
.nuget\NuGet.Config = .nuget\NuGet.Config
.nuget\NuGet.exe = .nuget\NuGet.exe
.nuget\NuGet.targets = .nuget\NuGet.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{41C66594-D42A-4FE1-B651-95185B6D70EB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Breeze.Services", "Services\Breeze.Services\Breeze.Services.csproj", "{F02F6D71-F6C9-46D8-8D9E-5BD8CEB97D8A}"
......
......@@ -48,22 +48,42 @@
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.ReaderWriter" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<applicationSettings>
<Breeze.CMS.Properties.Settings>
<setting name="TempFileStorage" serializeAs="String">
<value>%TEMP%\BREEZECMS</value>
</setting>
<setting name="SiteCanonicalName" serializeAs="String">
<value>http://localhost:50477/</value>
</setting>
<setting name="NotificationSenderEmail" serializeAs="String">
<value>noreply@localhost</value>
</setting>
<setting name="NotificationSenderName" serializeAs="String">
<value>BREEZE.CMS</value>
</setting>
</Breeze.CMS.Properties.Settings>
<setting name="TempFileStorage" serializeAs="String">
<value>%TEMP%\BREEZECMS</value>
</setting>
<setting name="SiteCanonicalName" serializeAs="String">
<value>http://localhost:50477/</value>
</setting>
<setting name="NotificationSenderEmail" serializeAs="String">
<value>noreply@localhost</value>
</setting>
<setting name="NotificationSenderName" serializeAs="String">
<value>BREEZE.CMS</value>
</setting>
</Breeze.CMS.Properties.Settings>
</applicationSettings>
</configuration>
\ No newline at end of file
This diff is collapsed.
using Breeze.Data;
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Description;
using System.Linq.Dynamic;
using System.Reflection;
using System.Security;
using log4net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Results;
namespace Breeze.CMS.Controllers {
/// <summary>
/// Base API controller that provides data access functionality.
/// Stored entity shound have single field primary key.
/// </summary>
/// <typeparam name="TEntity">The stored entity type.</typeparam>
/// <typeparam name="TModel">The transport model.</typeparam>
/// <typeparam name="TKey">The type of key field.</typeparam>
public abstract class DataApiController<TEntity, TModel, TKey> : ApiController
where TEntity : class, new()
where TModel : class, new() {
Expression<Func<TEntity, TModel>> _defaultSelectExpression;
protected readonly ILog _log;
/// <summary>
/// Data Repository
/// </summary>
public IRepository<TEntity> Repository { get; private set; }
protected DataApiController(IRepository<TEntity> repository) {
Repository = repository;
_log = LogManager.GetLogger(this.GetType());
_log.Debug("Controller created.");
_log.Debug($"{this.GetType().Name} created.");
}
protected override void Dispose(bool disposing) {
_log.Debug("Controller disposed.");
_log.Debug($"{this.GetType().Name} disposed.");
base.Dispose(disposing);
}
public virtual IHttpActionResult GetEntity(TKey id) {
var entity = Repository.Load(id);
public virtual async Task<IHttpActionResult> GetEntity(TKey id) {
var entity = await Repository.LoadAsync(id);
if (entity == null)
return NotFound();
......@@ -45,7 +51,7 @@ namespace Breeze.CMS.Controllers {
return Ok(model);
}
public virtual IHttpActionResult PostEntity(TModel model) {
public virtual async Task<IHttpActionResult> PostEntity(TModel model) {
if (!ModelState.IsValid)
return BadRequest(ModelState);
......@@ -53,39 +59,51 @@ namespace Breeze.CMS.Controllers {
return StatusCode(HttpStatusCode.Forbidden);
var entity = Repository.Insert(new TEntity());
UpdateEntity(entity, model);
Repository.Save();
UpdateEntity(entity, model, true);
await SaveAsync();
return CreatedAtRoute("DefaultApi", new { id = GetEntityId(entity) }, ConvertEntityToModel(entity));
}
public virtual IHttpActionResult PutEntity(TModel model) {
public virtual async Task<IHttpActionResult> PutEntity(TModel model) {
if (!ModelState.IsValid)
return BadRequest(ModelState);
var entity = Repository.Load(GetModelId(model));
var entity = await Repository.LoadAsync(GetModelId(model));
if (entity == null)
return NotFound();
if (!IsAuthorizedWithLogging(AccessType.Update, entity, model))
return StatusCode(HttpStatusCode.Forbidden);
UpdateEntity(entity, model);
UpdateEntity(entity, model, false);
await SaveAsync();
return StatusCode(HttpStatusCode.NoContent);
}
public virtual IHttpActionResult RemoveEntity(TKey id) {
var entity = Repository.Load(id);
public virtual async Task<IHttpActionResult> DeleteEntity(TKey id) {
var entity = await Repository.LoadAsync(id);
if (entity == null)
return NotFound();
if (!IsAuthorizedWithLogging(AccessType.Delete, entity))
return StatusCode(HttpStatusCode.Forbidden);
// fill model before removing
var model = ConvertEntityToModel(entity);
// remove
Repository.Remove(entity);
await SaveAsync();
return Ok(model);
}
protected virtual void Save() {
Repository.Save();
}
return Ok(ConvertEntityToModel(entity));
protected virtual Task<int> SaveAsync() {
return Repository.SaveAsync();
}
protected virtual Expression<Func<TEntity, TModel>> SearchSelectExpression {
......@@ -98,6 +116,12 @@ namespace Breeze.CMS.Controllers {
}
}
protected virtual Expression<Func<TEntity, TModel>> GetSelectExpression { get { return SearchSelectExpression; } }
protected virtual bool IsAuthorized(AccessType type, TEntity entity = null, TModel model = null) {
return true;
}
#region Helper methods
protected virtual TKey GetModelId(TModel model) {
return (TKey)typeof(TModel).GetProperty("Id").GetValue(model);
}
......@@ -107,12 +131,10 @@ namespace Breeze.CMS.Controllers {
protected virtual TModel ConvertEntityToModel(TEntity entity) {
return GetSelectExpression.Compile().Invoke(entity);
}
protected virtual void UpdateEntity(TEntity entity, TModel model) {
model.AutoCopyTo(entity);
}
protected virtual bool IsAuthorized(AccessType type, TEntity entity = null, TModel model = null) {
return true;
protected virtual TEntity UpdateEntity(TEntity entity, TModel model, bool isNew) {
model.AutoCopyTo(entity);
return entity;
}
protected bool IsAuthorizedWithLogging(AccessType type, TEntity entity = null, TModel model = null) {
......@@ -126,12 +148,16 @@ namespace Breeze.CMS.Controllers {
throw new SecurityException();
}
public enum AccessType {
Create,
Read,
Update,
Delete
protected StatusCodeResult Forbidden() {
return StatusCode(HttpStatusCode.Forbidden);
}
#endregion
}
public enum AccessType {
Create,
Read,
Update,
Delete
}
}
\ No newline at end of file
using Breeze.Data;
using log4net;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Description;
using System.Linq.Dynamic;
using System.Reflection;
using System.Security;
using System.Web.OData;
using System.Threading.Tasks;
using System.Data.Entity.Infrastructure;
using System.Data.Entity;
using log4net;
using System.Web.Http;
using System.Web.OData;
namespace Breeze.CMS.Controllers {
public abstract class ODataControllerBase<TEntity, TModel, TKey> : ODataController
where TEntity : class, new()
where TModel : class, new() {
Expression<Func<TEntity, TModel>> _defaultSelectExpression;
ILog _log;
protected readonly ILog _log;
public IRepository<TEntity> Repository { get; private set; }
......@@ -41,13 +37,13 @@ namespace Breeze.CMS.Controllers {
if (!IsAuthorizedWithLogging(AccessType.Read))
return StatusCode(HttpStatusCode.Forbidden);
return Ok(Repository.Search(PreFilterExpression).Select(SearchSelectExpression));
return Ok(Repository.Search(PreFilterExpression, false).Select(SearchSelectExpression));
}
[EnableQuery]
public virtual IHttpActionResult Get([FromODataUri] TKey key) {
var modelQuery = Repository
.Search(PreFilterExpression)
.Search(PreFilterExpression, false)
.Where(GetFilterByKeyExpression(key))
.Select(SearchSelectExpression);
......@@ -65,10 +61,10 @@ namespace Breeze.CMS.Controllers {
return StatusCode(HttpStatusCode.Forbidden);
var entity = Repository.Insert(new TEntity());
UpdateEntity(entity, model);
await Repository.SaveAsync();
UpdateEntity(entity, model, true);
await SaveAsync();
return Created(ConvertEntityToModel(entity));
return Created(ConvertEntityToModel(await LoadEntityAsync(GetEntityId(entity), false)));
}
public virtual async Task<IHttpActionResult> Put([FromODataUri] TKey key, TModel model) {
......@@ -78,7 +74,7 @@ namespace Breeze.CMS.Controllers {
TKey modelId = GetModelId(model);
if (!modelId.Equals(key))
return BadRequest();
TEntity entity = LoadEntity(modelId);
TEntity entity = await LoadEntityAsync(modelId, true);
if (entity == null)
return NotFound();
......@@ -86,24 +82,34 @@ namespace Breeze.CMS.Controllers {
return StatusCode(HttpStatusCode.Forbidden);
UpdateEntity(entity, model);
await Repository.SaveAsync();
UpdateEntity(entity, model, false);
await SaveAsync();
return Updated(ConvertEntityToModel(entity));
return Updated(ConvertEntityToModel(await LoadEntityAsync(key, false)));
}
protected TEntity LoadEntity(TKey modelId) {
protected TEntity LoadEntity(TKey modelId, bool tracking) {
return Repository
.Search(PreFilterExpression)
.Search(PreFilterExpression, tracking)
.Where(GetFilterByKeyExpression(modelId))
.FirstOrDefault();
}
protected Task<TEntity> LoadEntityAsync(TKey modelId, bool tracking) {
var query = Repository
.Search(PreFilterExpression, tracking)
.Where(GetFilterByKeyExpression(modelId));
if (query is IDbAsyncQueryProvider)
return query.FirstOrDefaultAsync();
else
return Task.FromResult(query.FirstOrDefault());
}
public virtual async Task<IHttpActionResult> Patch([FromODataUri] TKey key, Delta<TModel> model) {
if (!ModelState.IsValid)
return BadRequest(ModelState);
var entity = LoadEntity(key);
var entity = await LoadEntityAsync(key, true);
if (entity == null)
return NotFound();
......@@ -117,22 +123,22 @@ namespace Breeze.CMS.Controllers {
if (!IsAuthorizedWithLogging(AccessType.Update, entity, fullModel))
return StatusCode(HttpStatusCode.Forbidden);
UpdateEntity(entity, fullModel);
UpdateEntity(entity, fullModel, false);
await Repository.SaveAsync();
await SaveAsync();
return Updated(fullModel);
return Updated(LoadEntityAsync(key, false));
}
public virtual async Task<IHttpActionResult> Delete([FromODataUri] TKey key) {
var entity = LoadEntity(key);
var entity = await LoadEntityAsync(key, true);
if (entity == null)
return NotFound();
if (!IsAuthorizedWithLogging(AccessType.Delete, entity))
return StatusCode(HttpStatusCode.Forbidden);
Repository.Remove(entity);
await Repository.SaveAsync();
await SaveAsync();
return Ok();
}
......@@ -142,7 +148,9 @@ namespace Breeze.CMS.Controllers {
return Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(Expression.Property(x, "Id"), Expression.Constant(key)), x);
}
protected virtual bool EntityExists(TKey key) {
return Repository.Search(PreFilterExpression).Any(GetFilterByKeyExpression(key));
return Repository
.Search(PreFilterExpression, false)
.Any(GetFilterByKeyExpression(key));
}
protected virtual Expression<Func<TEntity, bool>> PreFilterExpression {
......@@ -163,6 +171,14 @@ namespace Breeze.CMS.Controllers {
protected virtual Expression<Func<TEntity, TModel>> ConvertToModelExpression { get { return SearchSelectExpression; } }
protected virtual void Save() {
Repository.Save();
}
protected virtual Task<int> SaveAsync() {
return Repository.SaveAsync();
}
protected virtual TKey GetModelId(TModel model) {
return (TKey)typeof(TModel).GetProperty("Id").GetValue(model);
}
......@@ -172,8 +188,8 @@ namespace Breeze.CMS.Controllers {
protected virtual TModel ConvertEntityToModel(TEntity entity) {
return ConvertToModelExpression.Compile().Invoke(entity);
}
protected virtual void UpdateEntity(TEntity entity, TModel model) {
model.AutoCopyTo(entity);
protected virtual TEntity UpdateEntity(TEntity entity, TModel model, bool isNew) {
return model.AutoCopyTo(entity);
}
protected virtual bool IsAuthorized(AccessType type, TEntity entity = null, TModel model = null) {
......@@ -222,10 +238,13 @@ namespace Breeze.CMS.Controllers {
if (!IsAuthorizedWithLogging(AccessType.Create, null, model))
return StatusCode(HttpStatusCode.Forbidden);
Repository.Insert(model);
await Repository.SaveAsync();
var entity = new TEntity();
UpdateEntity(entity, model, true);
Repository.Insert(entity);
await SaveAsync();
return Created(model);
return Created(await LoadEntityAsync(GetEntityId(entity), false));
}
public override async Task<IHttpActionResult> Put([FromODataUri] TKey key, TEntity model) {
......@@ -239,23 +258,28 @@ namespace Breeze.CMS.Controllers {
if (!IsAuthorizedWithLogging(AccessType.Update, null, model))
return StatusCode(HttpStatusCode.Forbidden);
Repository.Update(model);
var entity = await LoadEntityAsync(modelId, true);
if (entity == null)
return NotFound();
UpdateEntity(entity, model, false);
Repository.Update(entity);
try {
await Repository.SaveAsync();
await SaveAsync();
} catch (DbUpdateConcurrencyException) {
if (!EntityExists(key))
return NotFound();
else
throw;
}
return Updated(model);
return Updated(await LoadEntityAsync(key, false));
}
public override async Task<IHttpActionResult> Patch([FromODataUri] TKey key, Delta<TEntity> model) {
if (!ModelState.IsValid)
return BadRequest(ModelState);
var entity = LoadEntity(key);
var entity = await LoadEntityAsync(key, true);
if (entity == null)
return NotFound();
......@@ -264,9 +288,10 @@ namespace Breeze.CMS.Controllers {
if (!IsAuthorizedWithLogging(AccessType.Update, entity, entity))
return StatusCode(HttpStatusCode.Forbidden);
await Repository.SaveAsync();
UpdateEntity(entity, entity, false);
await SaveAsync();
return Updated(entity);
return Updated(await LoadEntityAsync(key, false));
}
}
}
......@@ -52,14 +52,16 @@ namespace Breeze.CMS.Controllers {
return await base.Post(model);
}
protected override void UpdateEntity(TPost entity, TPostModel model) {
base.UpdateEntity(entity, model);
protected override TPost UpdateEntity(TPost entity, TPostModel model, bool isNew) {
base.UpdateEntity(entity, model, isNew);
if (entity.Author == null)
entity.Author = _userRepository.Value.Load(entity.AuthorId);
if (entity.Comments == null)
entity.Comments = new List<TComment>();
return entity;
}
}
}
using Breeze.CMS.Entities;
using Breeze.CMS.Models;
using Breeze.CMS.Properties;
using Breeze.CMS.Services;
using Breeze.Data;
using Microsoft.AspNet.Identity;
using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Linq;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Web.Http;
using Breeze.CMS.Properties;
namespace Breeze.CMS.Controllers {
public abstract class UsersController<TUser, TModel, TKey, TUserManager> : DataApiController<TUser, TModel, int>
where TUser : class, ICmsUser<TKey>, new()
where TKey : IEquatable<TKey>, IConvertible
where TModel : class, new()
where TModel : UserModel, new()
where TUserManager : CmsUserManager<TUser, TKey> {
protected bool DefaultLockoutEnabled { get; set; } = true;
protected bool DefaultTwoFactorEnabled { get; set; } = false;
protected IUnitOfWork UnitOfWork { get; private set; }
protected Lazy<TUserManager> UserManager { get; private set; }
public UsersController(IRepository<TUser> userRepository, Lazy<TUserManager> userManager) : base(userRepository) {
public UsersController(IUnitOfWork unitOfWork, IRepository<TUser> userRepository, Lazy<TUserManager> userManager) : base(userRepository) {
UnitOfWork = unitOfWork;
UserManager = userManager;
}
......@@ -33,67 +32,61 @@ namespace Breeze.CMS.Controllers {
case AccessType.Delete:
return entity != null && User.Identity.IsAuthenticated && entity.Id.Equals(User.Identity.GetUserId<TKey>());
case AccessType.Create:
return true;
return true; // allow user self-registration by default
default:
return false;
}
}
[Route("register")]
// allow anonymous for self-registration purposes
[HttpPost, AllowAnonymous]
public virtual async Task<IHttpActionResult> Register(RegisterUserModel model) {
if (!ModelState.IsValid)
{
_log.InfoFormat("First bad request");
return BadRequest(ModelState);
}
if (!IsAuthorizedWithLogging(AccessType.Create, null, null))
return Unauthorized();
var now = DateTime.Now;
var user = new TUser {
UserName = model.UserName,
Email = model.Email,
PhoneNumber = model.Phone,
DateCreated = now,
DateUpdated = now,
LastActivityDate = now,
public override async Task<IHttpActionResult> PostEntity(TModel model) {
if (!ModelState.IsValid) {
_log.InfoFormat("First bad request");
return BadRequest(ModelState);
}
// verify permissions
if (!IsAuthorizedWithLogging(AccessType.Create, null, model))
return Forbidden();
// create entity
var user = UpdateEntity(new TUser {
TwoFactorEnabled = DefaultTwoFactorEnabled,
LockoutEnabled = DefaultLockoutEnabled,
LastPasswordChangedDate = now,
TwoFactorEnabled = DefaultTwoFactorEnabled
};
// check for unique values
var emailRes = await UserManager.Value.FindByEmailAsync(model.Email);
if (null != emailRes)
ModelState.AddModelError("Email", String.Format(Resources.EmailUnique, model.Email));
var nameRes = await UserManager.Value.FindByNameAsync(model.UserName);
if (null != nameRes)
ModelState.AddModelError("UserName", String.Format(Resources.UserNameUnique, model.UserName));
var res = await UserManager.Value.CreateAsync(user, model.Password);
/*if (!res.Succeeded)
{
// all errors
foreach (var e in res.Errors)
ModelState.AddModelError("", e);
}*/
if (!res.Succeeded)
{
return BadRequest(ModelState);
}
else
{
_log.InfoFormat("New user registered. UserName = {0}", model.UserName);
await OnUserRegisteredAsync(user);
return Ok();
}
LastPasswordChangedDate = DateTime.UtcNow
}, model, true);
using (var scope = UnitOfWork.Begin()) {
// check for unique values
var emailRes = await UserManager.Value.FindByEmailAsync(model.Email);
if (null != emailRes)
ModelState.AddModelError("Email", String.Format(Resources.EmailUnique, model.Email));
var nameRes = await UserManager.Value.FindByNameAsync(model.UserName);
if (null != nameRes)
ModelState.AddModelError("UserName", String.Format(Resources.UserNameUnique, model.UserName));
// create user
if (ModelState.IsValid) {
var res = await UserManager.Value.CreateAsync(user, model.Password);
if (res.Succeeded) {
_log.InfoFormat("New user registered. UserName = {0}", model.UserName);
user = Repository.Search(x => x.UserName == model.UserName, false).First();
model = ConvertEntityToModel(user);
await OnUserRegisteredAsync(user);
scope.Commit();
return CreatedAtRoute("DefaultApi", new { id = user.Id }, model);
} else
foreach (var e in res.Errors)
ModelState.AddModelError("", e);
}
}
return BadRequest(ModelState);
}
[Route("forgot")]
[HttpPost, AllowAnonymous]
public virtual async Task<IHttpActionResult> Forgot(ForgetPasswordModel model) {
if (String.IsNullOrWhiteSpace(model.Email))
......@@ -106,7 +99,6 @@ namespace Breeze.CMS.Controllers {
return NotFound();
}
[Route("password")]
[HttpPost, AllowAnonymous]
public virtual async Task<IHttpActionResult> Password(SetPasswordModel model) {
if (String.IsNullOrWhiteSpace(model.NewPassword))
......@@ -125,8 +117,25 @@ namespace Breeze.CMS.Controllers {
return res.Succeeded ? (IHttpActionResult)Ok() : BadRequest(String.Join("\n", res.Errors));
}
protected virtual async Task OnUserRegisteredAsync(TUser user) {
await UserManager.Value.NotifyUserRegisteredAsync(user);
protected virtual Task OnUserRegisteredAsync(TUser user) {
return UserManager.Value.NotifyUserRegisteredAsync(user);
}
protected override TUser UpdateEntity(TUser entity, TModel model, bool isNew) {
DateTime now = DateTime.UtcNow;
entity.Email = model.Email;
entity.FirstName = model.FirstName;
entity.LastName = model.LastName;
entity.MustChangePassword = model.MustChangePassword;
entity.PhoneNumber = model.PhoneNumber;
entity.PictureId = model.PictureId;
entity.Status = model.Status;
entity.UpdateDate = now;
entity.UserName = model.UserName;
if (isNew)
entity.CreateDate = now;
return entity;
}
}
}
......@@ -27,9 +27,9 @@ namespace Breeze.CMS.Entities {
public long? PictureId { get; set; }
public virtual File Picture { get; set; }
public UserStatus Status { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
public DateTime? DateDeleted { get; set; }
public DateTime CreateDate { get; set; }
public DateTime UpdateDate { get; set; }
public DateTime? DeleteDate { get; set; }
public DateTime? LastActivityDate { get; set; }
public DateTime LastPasswordChangedDate { get; set; }
[DefaultValue(true)]
......@@ -39,7 +39,9 @@ namespace Breeze.CMS.Entities {
public enum UserStatus {
Active = 0,
Inactive = 1,
Deleted = 2
Deleted = 2,
// virtual/runtime statuses (are not stored in db)
LockedOut = 1000
}
public class CmsRole<TKey, TUserRole> : IdentityRole<TKey, TUserRole>
where TKey : System.IEquatable<TKey>
......
......@@ -6,9 +6,9 @@ namespace Breeze.CMS.Entities {
public interface ICmsUser<out TKey> : IUser<TKey> {
string Email { get; set; }
string PhoneNumber { get; set; }
DateTime DateCreated { get; set; }
DateTime? DateDeleted { get; set; }
DateTime DateUpdated { get; set; }
DateTime CreateDate { get; set; }
DateTime? DeleteDate { get; set; }
DateTime UpdateDate { get; set; }
string FirstName { get; set; }
DateTime? LastActivityDate { get; set; }
string LastName { get; set; }
......
......@@ -138,7 +138,7 @@ namespace Breeze.CMS.Maps {
new IndexAnnotation(
new IndexAttribute("IX_UserName") { IsUnique = true, Order = 0 }
));
user.Property(x => x.DateDeleted)
user.Property(x => x.DeleteDate)
.HasColumnAnnotation(IndexAnnotation.AnnotationName,
new IndexAnnotation(
new IndexAttribute("IX_UserName") { IsUnique = true, Order = 1 }
......
......@@ -39,16 +39,21 @@ namespace Breeze.CMS.Models {
public int Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public long? PictureId { get; set; }
public UserStatus Status { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
public DateTime CreateDate { get; set; }
public DateTime UpdateDate { get; set; }
public DateTime? LastActivityDate { get; set; }
public DateTime LastPasswordChangedDate { get; set; }
public bool MustChangePassword { get; set; }
}
/// <summary>
/// This property is used to set password. Server should never return password to client!
/// </summary>
public string Password { get; set; }
}
public class UserModelList : CollectionFrame<UserModel> {
public UserModelList(UserModelList original) : base(original) { }
......
......@@ -61,7 +61,7 @@ namespace Breeze.CMS.Properties {
}
/// <summary>
/// Looks up a localized string similar to Задовгий Email.
/// Looks up a localized string similar to Max email length reached.
/// </summary>
internal static string EmailStringLength {
get {
......@@ -70,7 +70,7 @@ namespace Breeze.CMS.Properties {
}
/// <summary>
/// Looks up a localized string similar to Email {0} вже присутній.
/// Looks up a localized string similar to Email {0} already exists.
/// </summary>
internal static string EmailUnique {
get {
......@@ -79,7 +79,7 @@ namespace Breeze.CMS.Properties {
}
/// <summary>
/// Looks up a localized string similar to Ім&apos;я некоректної довжини.
/// Looks up a localized string similar to Incorrect Name length.
/// </summary>
internal static string UserNameStringLength {
get {
......@@ -88,7 +88,7 @@ namespace Breeze.CMS.Properties {
}
/// <summary>
/// Looks up a localized string similar to Користувач з іменем {0} вже присутній.
/// Looks up a localized string similar to User {0} already exists.
/// </summary>
internal static string UserNameUnique {
get {
......
......@@ -118,15 +118,15 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="EmailStringLength" xml:space="preserve">
<value>Задовгий Email</value>
<value>Max email length reached</value>
</data>
<data name="EmailUnique" xml:space="preserve">
<value>Email {0} вже присутній</value>
<value>Email {0} already exists</value>
</data>
<data name="UserNameStringLength" xml:space="preserve">
<value>Ім'я некоректної довжини</value>
<value>Incorrect Name length</value>
</data>
<data name="UserNameUnique" xml:space="preserve">
<value>Користувач з іменем {0} вже присутній</value>
<value>User {0} already exists</value>
</data>
</root>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="EmailStringLength" xml:space="preserve">
<value>Задовгий Email</value>
</data>
<data name="EmailUnique" xml:space="preserve">
<value>Email {0} вже існує</value>
</data>
<data name="UserNameStringLength" xml:space="preserve">
<value>Ім'я некоректної довжини</value>
</data>
<data name="UserNameUnique" xml:space="preserve">
<value>Користувач з іменем {0} вже існує</value>
</data>
</root>
\ No newline at end of file
......@@ -2,21 +2,14 @@
using Breeze.Data.Media;
using log4net;
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Infrastructure.Annotations;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Breeze.CMS.Services {
public abstract class CmsDbContext<TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim, TFile, TFileCache> : IdentityDbContext<TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim>
namespace Breeze.CMS.Services
{
public abstract class CmsDbContext<TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim, TFile, TFileCache> : IdentityDbContext<TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim>
where TKey : System.IEquatable<TKey>
where TUser : CmsUser<TKey, TUserLogin, TUserRole, TUserClaim>
where TRole : CmsRole<TKey, TUserRole>
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="6.1.3" targetFramework="net461" />
<package id="LinqKit" version="1.1.7.3" targetFramework="net461" />
<package id="LinqKit" version="1.1.8.0" targetFramework="net461" />
<package id="log4net" version="2.0.5" targetFramework="net461" />
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net461" />
<package id="Microsoft.AspNet.Identity.EntityFramework" version="2.2.1" targetFramework="net461" />
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net461" />
<package id="Microsoft.AspNet.OData" version="5.9.1" targetFramework="net461" />
<package id="Microsoft.AspNet.OData" version="6.0.0" targetFramework="net461" />
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net461" />
<package id="Microsoft.Extensions.DependencyInjection" version="1.0.0" targetFramework="net461" />
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="1.0.0" targetFramework="net461" />
<package id="Microsoft.OData.Core" version="6.15.0" targetFramework="net461" />
<package id="Microsoft.OData.Edm" version="6.15.0" targetFramework="net461" />
<package id="Microsoft.Extensions.DependencyInjection" version="1.1.0" targetFramework="net461" />
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="1.1.0" targetFramework="net461" />
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net461" />
<package id="Microsoft.OData.Core" version="7.0.0" targetFramework="net461" />
<package id="Microsoft.OData.Edm" version="7.0.0" targetFramework="net461" />
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net461" />
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net461" />
<package id="Microsoft.Owin.Security.Cookies" version="3.0.1" targetFramework="net461" />
<package id="Microsoft.Owin.Security.OAuth" version="3.0.1" targetFramework="net461" />
<package id="Microsoft.Spatial" version="6.15.0" targetFramework="net461" />
<package id="Microsoft.Spatial" version="7.0.0" targetFramework="net461" />
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net461" />
<package id="NETStandard.Library" version="1.6.1" targetFramework="net461" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" />
<package id="Owin" version="1.0" targetFramework="net461" />
<package id="RazorEngine" version="3.9.0" targetFramework="net461" />
<package id="System.Collections" version="4.0.11" targetFramework="net461" />
<package id="System.Collections.Concurrent" version="4.0.12" targetFramework="net461" />
<package id="System.ComponentModel" version="4.0.1" targetFramework="net461" />
<package id="System.Diagnostics.Debug" version="4.0.11" targetFramework="net461" />
<package id="System.Globalization" version="4.0.11" targetFramework="net461" />
<package id="System.Linq" version="4.1.0" targetFramework="net461" />
<package id="System.Linq.Dynamic" version="1.0.6" targetFramework="net461" />
<package id="System.Linq.Expressions" version="4.1.0" targetFramework="net461" />
<package id="System.Reflection" version="4.1.0" targetFramework="net461" />
<package id="System.Resources.ResourceManager" version="4.0.1" targetFramework="net461" />
<package id="System.Runtime.Extensions" version="4.1.0" targetFramework="net461" />
<package id="System.Threading" version="4.0.11" targetFramework="net461" />
<package id="System.Threading.Tasks" version="4.0.11" targetFramework="net461" />
<package id="RazorEngine" version="3.9.3" targetFramework="net461" />
<package id="System.AppContext" version="4.3.0" targetFramework="net461" />
<package id="System.Collections" version="4.3.0" targetFramework="net461" />
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" />
<package id="System.ComponentModel" version="4.3.0" targetFramework="net461" />
<package id="System.Console" version="4.3.0" targetFramework="net461" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
<package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net461" />
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" />
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net461" />
<package id="System.Globalization" version="4.3.0" targetFramework="net461" />
<package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net461" />
<package id="System.IO" version="4.3.0" targetFramework="net461" />
<package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net461" />
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
<package id="System.Linq" version="4.3.0" targetFramework="net461" />
<package id="System.Linq.Dynamic" version="1.0.7" targetFramework="net461" />
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
<package id="System.Net.Http" version="4.3.0" targetFramework="net461" />
<package id="System.Net.Primitives" version="4.3.0" targetFramework="net461" />
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net461" />
<package id="System.ObjectModel" version="4.3.0" targetFramework="net461" />
<package id="System.Reflection" version="4.3.0" targetFramework="net461" />
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net461" />
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net461" />
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" />
<package id="System.Runtime" version="4.3.0" targetFramework="net461" />
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net461" />
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" />
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" />
<package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net461" />
<package id="System.Threading" version="4.3.0" targetFramework="net461" />
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" />
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net461" />
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" />
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" />
</packages>
\ No newline at end of file
......@@ -45,15 +45,15 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll</HintPath>
</Reference>
<Reference Include="LinqKit, Version=1.1.7.3, Culture=neutral, PublicKeyToken=bc217f8844052a91, processorArchitecture=MSIL">
<HintPath>..\packages\LinqKit.1.1.7.3\lib\net45\LinqKit.dll</HintPath>
<Reference Include="LinqKit, Version=1.1.8.0, Culture=neutral, PublicKeyToken=bc217f8844052a91, processorArchitecture=MSIL">
<HintPath>..\packages\LinqKit.1.1.8.0\lib\net45\LinqKit.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Linq.Dynamic, Version=1.0.5840.25917, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\System.Linq.Dynamic.1.0.6\lib\net40\System.Linq.Dynamic.dll</HintPath>
<Reference Include="System.Linq.Dynamic, Version=1.0.6132.35681, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\System.Linq.Dynamic.1.0.7\lib\net40\System.Linq.Dynamic.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
......
......@@ -5,8 +5,8 @@ using System.Threading.Tasks;
namespace Breeze.Data {
public interface IRepository<TEntity> where TEntity : class {
IQueryable<TEntity> Search(Expression<Func<TEntity, bool>> predicate = null);
IQueryable<TDesendantEntity> Search<TDesendantEntity>(Expression<Func<TDesendantEntity, bool>> predicate = null) where TDesendantEntity : TEntity;
IQueryable<TEntity> Search(Expression<Func<TEntity, bool>> predicate = null, bool tracking = true);
IQueryable<TDesendantEntity> Search<TDesendantEntity>(Expression<Func<TDesendantEntity, bool>> predicate = null, bool tracking = true) where TDesendantEntity : TEntity;
int Count<TDesendantEntity>(Expression<Func<TDesendantEntity, bool>> predicate = null) where TDesendantEntity : TEntity;
TEntity Load(params object[] key);
TEntity Insert(TEntity entry);
......@@ -20,5 +20,7 @@ namespace Breeze.Data {
public interface IEFRepository {
IDbContext Context { get; }
void Detach(object entity);
void Reload(object entity);
}
}
......@@ -12,14 +12,18 @@ namespace Breeze.Data {
this.Context = context;
}
public IQueryable<TEntity> Search(Expression<Func<TEntity, bool>> predicate = null) {
return Search<TEntity>(predicate);
public IQueryable<TEntity> Search(Expression<Func<TEntity, bool>> predicate = null, bool tracking = true) {
return Search<TEntity>(predicate, tracking);
}
public virtual IQueryable<TDescendantEntity> Search<TDescendantEntity>(Expression<Func<TDescendantEntity, bool>> predicate = null) where TDescendantEntity : TEntity {
return predicate == null
? Context.Set<TEntity>().OfType<TDescendantEntity>()
: Context.Set<TEntity>().OfType<TDescendantEntity>().AsExpandable().Where(predicate);
public virtual IQueryable<TDescendantEntity> Search<TDescendantEntity>(Expression<Func<TDescendantEntity, bool>> predicate = null, bool tracking = true) where TDescendantEntity : TEntity {
var dbset = tracking
? Context.Set<TEntity>()
: Context.Set<TEntity>().AsNoTracking();
return predicate == null
? dbset.OfType<TDescendantEntity>()
: dbset.OfType<TDescendantEntity>().AsExpandable().Where(predicate);
}
public virtual int Count<TDescendantEntity>(Expression<Func<TDescendantEntity, bool>> predicate = null) where TDescendantEntity : TEntity {
......@@ -64,5 +68,13 @@ namespace Breeze.Data {
public virtual Task<int> SaveAsync() {
return Context.SaveChangesAsync();
}
}
public virtual void Reload(object entity) {
Context.Entry(entity).Reload();
}
public virtual void Detach(object entity) {
Context.Entry(entity).State = System.Data.Entity.EntityState.Detached;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="6.1.3" targetFramework="net45" />
<package id="LinqKit" version="1.1.7.3" targetFramework="net45" />
<package id="System.Linq.Dynamic" version="1.0.6" targetFramework="net45" />
<package id="LinqKit" version="1.1.8.0" targetFramework="net45" />
<package id="System.Linq.Dynamic" version="1.0.7" targetFramework="net45" />
</packages>
\ No newline at end of file
......@@ -24,15 +24,15 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.7.0.0" newVersion="5.7.0.0" />
<bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.7.0.0" newVersion="5.7.0.0" />
<bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.7.0.0" newVersion="5.7.0.0" />
<bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
......
......@@ -50,24 +50,24 @@
<HintPath>..\..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Data.Edm, Version=5.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Data.Edm.5.7.0\lib\net40\Microsoft.Data.Edm.dll</HintPath>
<Reference Include="Microsoft.Data.Edm, Version=5.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Data.Edm.5.8.1\lib\net40\Microsoft.Data.Edm.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Data.OData, Version=5.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Data.OData.5.7.0\lib\net40\Microsoft.Data.OData.dll</HintPath>
<Reference Include="Microsoft.Data.OData, Version=5.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Data.OData.5.8.1\lib\net40\Microsoft.Data.OData.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Data.Services.Client, Version=5.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Data.Services.Client.5.7.0\lib\net40\Microsoft.Data.Services.Client.dll</HintPath>
<Reference Include="Microsoft.Data.Services.Client, Version=5.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Data.Services.Client.5.8.1\lib\net40\Microsoft.Data.Services.Client.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.WindowsAzure.Configuration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.1\lib\net40\Microsoft.WindowsAzure.Configuration.dll</HintPath>
<HintPath>..\..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.3\lib\net40\Microsoft.WindowsAzure.Configuration.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.WindowsAzure.Storage, Version=7.1.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\WindowsAzure.Storage.7.1.2\lib\net40\Microsoft.WindowsAzure.Storage.dll</HintPath>
<Reference Include="Microsoft.WindowsAzure.Storage, Version=7.2.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\WindowsAzure.Storage.7.2.1\lib\net40\Microsoft.WindowsAzure.Storage.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
......@@ -78,8 +78,8 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Services.Client" />
<Reference Include="System.Spatial, Version=5.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Spatial.5.7.0\lib\net40\System.Spatial.dll</HintPath>
<Reference Include="System.Spatial, Version=5.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Spatial.5.8.1\lib\net40\System.Spatial.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
......
......@@ -2,11 +2,11 @@
<packages>
<package id="EntityFramework" version="6.1.3" targetFramework="net45" />
<package id="Microsoft.Azure.KeyVault.Core" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.Data.Edm" version="5.7.0" targetFramework="net45" />
<package id="Microsoft.Data.OData" version="5.7.0" targetFramework="net45" />
<package id="Microsoft.Data.Services.Client" version="5.7.0" targetFramework="net45" />
<package id="Microsoft.WindowsAzure.ConfigurationManager" version="3.2.1" targetFramework="net45" />
<package id="Microsoft.Data.Edm" version="5.8.1" targetFramework="net45" />
<package id="Microsoft.Data.OData" version="5.8.1" targetFramework="net45" />
<package id="Microsoft.Data.Services.Client" version="5.8.1" targetFramework="net45" />
<package id="Microsoft.WindowsAzure.ConfigurationManager" version="3.2.3" targetFramework="net45" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
<package id="System.Spatial" version="5.7.0" targetFramework="net45" />
<package id="WindowsAzure.Storage" version="7.1.2" targetFramework="net45" />
<package id="System.Spatial" version="5.8.1" targetFramework="net45" />
<package id="WindowsAzure.Storage" version="7.2.1" targetFramework="net45" />
</packages>
\ No newline at end of file