diff --git a/BuildRevisionCounter.Contract/BuildRevisionCounter.Protocol.csproj b/BuildRevisionCounter.Contract/BuildRevisionCounter.Protocol.csproj new file mode 100644 index 0000000..d794d81 --- /dev/null +++ b/BuildRevisionCounter.Contract/BuildRevisionCounter.Protocol.csproj @@ -0,0 +1,54 @@ + + + + + Debug + AnyCPU + {667844E5-6D11-474D-A18F-BC4784626F34} + Library + Properties + BuildRevisionCounter.Protocol + BuildRevisionCounter.Protocol + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BuildRevisionCounter.Contract/Properties/AssemblyInfo.cs b/BuildRevisionCounter.Contract/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9f8219b --- /dev/null +++ b/BuildRevisionCounter.Contract/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BuildRevisionCounter.Contract")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BuildRevisionCounter.Contract")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("91410165-4321-4bb2-9665-c1c0e36dc1d4")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BuildRevisionCounter.Contract/Revision.cs b/BuildRevisionCounter.Contract/Revision.cs new file mode 100644 index 0000000..bf84c7a --- /dev/null +++ b/BuildRevisionCounter.Contract/Revision.cs @@ -0,0 +1,15 @@ +using System; + +namespace BuildRevisionCounter.Protocol +{ + public class Revision + { + public string Id { get; set; } + + public DateTime Created { get; set; } + + public DateTime Updated { get; set; } + + public long CurrentNumber { get; set; } + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Contract/User.cs b/BuildRevisionCounter.Contract/User.cs new file mode 100644 index 0000000..3ba213f --- /dev/null +++ b/BuildRevisionCounter.Contract/User.cs @@ -0,0 +1,11 @@ +namespace BuildRevisionCounter.Protocol +{ + public class User + { + public string Name { get; set; } + + public string Password { get; set; } + + public string[] Roles { get; set; } + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Core/BuildRevisionCounter.Core.csproj b/BuildRevisionCounter.Core/BuildRevisionCounter.Core.csproj new file mode 100644 index 0000000..99d5b9e --- /dev/null +++ b/BuildRevisionCounter.Core/BuildRevisionCounter.Core.csproj @@ -0,0 +1,92 @@ + + + + + Debug + AnyCPU + {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F} + Library + Properties + BuildRevisionCounter.Core + BuildRevisionCounter.Core + v4.5.1 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MongoDB.Bson.2.0.0\lib\net45\MongoDB.Bson.dll + True + + + ..\packages\MongoDB.Driver.2.0.0\lib\net45\MongoDB.Driver.dll + True + + + ..\packages\MongoDB.Driver.Core.2.0.0\lib\net45\MongoDB.Driver.Core.dll + True + + + ..\packages\mongocsharpdriver.2.0.0\lib\net45\MongoDB.Driver.Legacy.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + {667844e5-6d11-474d-a18f-bc4784626f34} + BuildRevisionCounter.Protocol + + + + + + + + + \ No newline at end of file diff --git a/BuildRevisionCounter.Core/Converters/IRevisionConverter.cs b/BuildRevisionCounter.Core/Converters/IRevisionConverter.cs new file mode 100644 index 0000000..e10d86b --- /dev/null +++ b/BuildRevisionCounter.Core/Converters/IRevisionConverter.cs @@ -0,0 +1,11 @@ +using BuildRevisionCounter.Core.DomainObjects; + +namespace BuildRevisionCounter.Core.Converters +{ + internal interface IRevisionConverter + { + Protocol.Revision ToProtocol(Revision revision); + + Revision ToDomain(Protocol.Revision revision); + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Core/Converters/IUserConverter.cs b/BuildRevisionCounter.Core/Converters/IUserConverter.cs new file mode 100644 index 0000000..3f74753 --- /dev/null +++ b/BuildRevisionCounter.Core/Converters/IUserConverter.cs @@ -0,0 +1,11 @@ +using BuildRevisionCounter.Core.DomainObjects; + +namespace BuildRevisionCounter.Core.Converters +{ + internal interface IUserConverter + { + Protocol.User ToProtocol(User user); + + User ToDomain(Protocol.User user); + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Core/Converters/Impl/RevisionConverter.cs b/BuildRevisionCounter.Core/Converters/Impl/RevisionConverter.cs new file mode 100644 index 0000000..b45cd2c --- /dev/null +++ b/BuildRevisionCounter.Core/Converters/Impl/RevisionConverter.cs @@ -0,0 +1,33 @@ +using BuildRevisionCounter.Core.DomainObjects; + +namespace BuildRevisionCounter.Core.Converters.Impl +{ + internal class RevisionConverter : IRevisionConverter + { + public Protocol.Revision ToProtocol(Revision revision) + { + var revisionProtocol = new Protocol.Revision + { + Id = revision.Id, + CurrentNumber = revision.CurrentNumber, + Updated = revision.Updated, + Created = revision.Created + }; + + return revisionProtocol; + } + + public Revision ToDomain(Protocol.Revision revision) + { + var revisionDomain = new Revision + { + Id = revision.Id, + CurrentNumber = revision.CurrentNumber, + Updated = revision.Updated, + Created = revision.Created + }; + + return revisionDomain; + } + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Core/Converters/Impl/UserConverter.cs b/BuildRevisionCounter.Core/Converters/Impl/UserConverter.cs new file mode 100644 index 0000000..60247a9 --- /dev/null +++ b/BuildRevisionCounter.Core/Converters/Impl/UserConverter.cs @@ -0,0 +1,21 @@ +using BuildRevisionCounter.Core.DomainObjects; + +namespace BuildRevisionCounter.Core.Converters.Impl +{ + internal class UserConverter : IUserConverter + { + public Protocol.User ToProtocol(User user) + { + var userProtocol = new Protocol.User { Name = user.Name, Password = user.Password, Roles = user.Roles }; + + return userProtocol; + } + + public User ToDomain(Protocol.User user) + { + var userDomain = new User { Name = user.Name, Password = user.Password, Roles = user.Roles }; + + return userDomain; + } + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Core/DomainObjects/Revision.cs b/BuildRevisionCounter.Core/DomainObjects/Revision.cs new file mode 100644 index 0000000..07ad49b --- /dev/null +++ b/BuildRevisionCounter.Core/DomainObjects/Revision.cs @@ -0,0 +1,20 @@ +using System; +using MongoDB.Bson.Serialization.Attributes; + +namespace BuildRevisionCounter.Core.DomainObjects +{ + internal class Revision + { + [BsonId] + public string Id; + + [BsonElement("created"), BsonDateTimeOptions(Kind = DateTimeKind.Utc)] + public DateTime Created; + + [BsonElement("updated"), BsonDateTimeOptions(Kind = DateTimeKind.Utc)] + public DateTime Updated; + + [BsonElement("currentNumber")] + public long CurrentNumber; + } +} \ No newline at end of file diff --git a/BuildRevisionCounter/Model/UserModel.cs b/BuildRevisionCounter.Core/DomainObjects/User.cs similarity index 76% rename from BuildRevisionCounter/Model/UserModel.cs rename to BuildRevisionCounter.Core/DomainObjects/User.cs index 8506596..2b280c0 100644 --- a/BuildRevisionCounter/Model/UserModel.cs +++ b/BuildRevisionCounter.Core/DomainObjects/User.cs @@ -1,8 +1,8 @@ using MongoDB.Bson.Serialization.Attributes; -namespace BuildRevisionCounter.Model +namespace BuildRevisionCounter.Core.DomainObjects { - public class UserModel + internal class User { [BsonId] public string Name { get; set; } diff --git a/BuildRevisionCounter.Core/MongoDBStorage.cs b/BuildRevisionCounter.Core/MongoDBStorage.cs new file mode 100644 index 0000000..5827f24 --- /dev/null +++ b/BuildRevisionCounter.Core/MongoDBStorage.cs @@ -0,0 +1,119 @@ +using System; +using System.Configuration; +using System.Threading.Tasks; +using BuildRevisionCounter.Core.DomainObjects; +using MongoDB.Driver; + +namespace BuildRevisionCounter.Core +{ + public class MongoContext : IRepository + { + public static readonly string AdminName = "admin"; + public static readonly string AdminPassword = "admin"; + public static readonly string[] AdminRoles = { "admin", "buildserver", "editor" }; + + private static readonly Object SLock = new Object(); + private static volatile MongoContext _instance = null; + + private readonly IMongoClient _client; + internal IMongoClient Client + { + get { return _client; } + } + + private readonly IMongoDatabase _database; + internal IMongoDatabase Database + { + get { return _database; } + } + + private MongoContext() + { + string connectionString = ConfigurationManager.ConnectionStrings["MongoDBStorage"].ConnectionString; + var url = new MongoUrl(connectionString); + + _client = new MongoClient(url); + _database = _client.GetDatabase(url.DatabaseName); + + CreateAdmin(); + } + + public static MongoContext Instance + { + get + { + if (_instance == null) + { + lock (SLock) + { + if (_instance == null) + _instance = new MongoContext(); + } + } + return _instance; + } + } + + public async Task SetUpAsync() + { + await Users.Indexes.CreateOneAsync( + Builders.IndexKeys.Ascending(u => u.Name), + new CreateIndexOptions { Unique = true }); + + await EnsureAdminUser(); + } + + public async Task DropDatabaseAsync() + { + await Client.DropDatabaseAsync(Database.DatabaseNamespace.DatabaseName); + } + + public async Task EnsureAdminUser() + { + var repository = RepositoryFactory.Instance.GetUserRepository(); + + if (await repository.CountAsync() == 0) + { + await repository.CreateUserAsync(new Protocol.User + { + Name = AdminName, + Password = AdminPassword, + Roles = AdminRoles + }); + } + } + + internal IMongoCollection Revisions + { + get { return _database.GetCollection("revisions"); } + } + + internal IMongoCollection Users + { + get { return _database.GetCollection("users"); } + } + + private void CreateAdmin() + { + var anyUser = Users.Find(l => true).FirstOrDefaultAsync(); + anyUser.Wait(); + + if (anyUser.Result == null) + { + Users.InsertOneAsync(new User + { + Name = "admin", + Password = "admin", + Roles = new[] { "admin", "buildserver", "editor" } + }); + } + } + } + + public interface IRepository + { + Task SetUpAsync(); + + Task DropDatabaseAsync(); + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Core/Properties/AssemblyInfo.cs b/BuildRevisionCounter.Core/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5118d0a --- /dev/null +++ b/BuildRevisionCounter.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BuildRevisionCounter.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BuildRevisionCounter.Core")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b1d43c9f-761a-420c-b9a9-c4beaa5f47f8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: InternalsVisibleTo("BuildRevisionCounter.Tests")] diff --git a/BuildRevisionCounter.Core/Repositories/IRevisionRepository.cs b/BuildRevisionCounter.Core/Repositories/IRevisionRepository.cs new file mode 100644 index 0000000..f974a21 --- /dev/null +++ b/BuildRevisionCounter.Core/Repositories/IRevisionRepository.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace BuildRevisionCounter.Core.Repositories +{ + public interface IRevisionRepository + { + Task GetRevisionByIdAsync(string revisionId); + + Task IncrementRevisionAsync(string revisionId); + + Task AddRevisionAsync(Protocol.Revision revision); + + Task ClearRevisionCollectionAsync(); + + Task> GetAllRevisionAsync(Int32 pageSize = 20, Int32 pageNumber = 1); + } +} diff --git a/BuildRevisionCounter.Core/Repositories/IUserRepository.cs b/BuildRevisionCounter.Core/Repositories/IUserRepository.cs new file mode 100644 index 0000000..3af44c2 --- /dev/null +++ b/BuildRevisionCounter.Core/Repositories/IUserRepository.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; + +namespace BuildRevisionCounter.Core.Repositories +{ + public interface IUserRepository + { + Task GetUserByNameAsync(string userName); + + Task CreateUserAsync(Protocol.User user); + + Task CountAsync(); + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Core/Repositories/Impl/RevisionRepository.cs b/BuildRevisionCounter.Core/Repositories/Impl/RevisionRepository.cs new file mode 100644 index 0000000..00757b8 --- /dev/null +++ b/BuildRevisionCounter.Core/Repositories/Impl/RevisionRepository.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using BuildRevisionCounter.Core.Converters; +using BuildRevisionCounter.Core.DomainObjects; +using MongoDB.Driver; + + +namespace BuildRevisionCounter.Core.Repositories.Impl +{ + internal class RevisionRepository : IRevisionRepository + { + private readonly MongoContext _storage; + private readonly IRevisionConverter _revisionConverter; + + public RevisionRepository(IRevisionConverter revisionConverter) + { + _storage = MongoContext.Instance; + _revisionConverter = revisionConverter; + } + + private void CheckRevisionId(string revisionId) + { + if (String.IsNullOrEmpty(revisionId)) throw new ArgumentException("revisionId can't be null or empty", "revisionId"); + } + + #region IRevisionRepository + + public async Task GetRevisionByIdAsync(string revisionId) + { + var domainRevision = await GetDomainRevisionByIdAsync(revisionId); + if (domainRevision == null) return null; + return _revisionConverter.ToProtocol(domainRevision); + } + + public async Task IncrementRevisionAsync(string revisionId) + { + var domainRevision = await IncrementDomainRevisionAsync(revisionId); + + return _revisionConverter.ToProtocol(domainRevision); + } + + public async Task AddRevisionAsync(Protocol.Revision revision) + { + var domainRevision = _revisionConverter.ToDomain(revision); + await AddDomainRevisionAsync(domainRevision); + } + + public async Task ClearRevisionCollectionAsync() + { + await _storage.Revisions.DeleteManyAsync(l => true); + } + + public async Task> GetAllRevisionAsync(Int32 pageSize = 20, Int32 pageNumber = 1) + { + var domainRevisions = await GetAllDomainRevisionAsync(pageSize, pageNumber); + + if (domainRevisions == null) return null; + var protocolRevisions = domainRevisions.Select(l => _revisionConverter.ToProtocol(l)).ToList(); + return protocolRevisions; + } + + #endregion + + internal async Task> GetAllDomainRevisionAsync(Int32 pageSize = 20, Int32 pageNumber = 1) + { + var revisions = await _storage.Revisions + .Find(r => true) + .Skip(pageSize * (pageNumber - 1)) + .Limit(pageSize) + .ToListAsync(); + + return revisions; + } + + internal async Task GetDomainRevisionByIdAsync(string revisionId) + { + CheckRevisionId(revisionId); + + var revision = await _storage.Revisions + .Find(_ => _.Id == revisionId) + .SingleOrDefaultAsync(); + + return revision; + } + + internal async Task IncrementDomainRevisionAsync(string revisionId) + { + CheckRevisionId(revisionId); + + // попробуем обновить документ + var result = await FindOneAndUpdateRevisionAsync(revisionId); + if (result != null) return result; + + // если не получилось, значит документ еще не был создан + // создадим его с начальным значением 0 + try + { + await _storage.Revisions + .InsertOneAsync(new Revision + { + Id = revisionId, + CurrentNumber = 0, + Created = DateTime.UtcNow + }); + + result = await GetDomainRevisionByIdAsync(revisionId); + return result; + } + catch (MongoWriteException ex) + { + if (ex.WriteError.Category != ServerErrorCategory.DuplicateKey) + throw; + } + + // если при вставке произошла ошибка значит мы не успели и запись там уже есть + // и теперь попытка обновления должна пройти без ошибок + result = await FindOneAndUpdateRevisionAsync(revisionId); + + return result; + } + + /// + /// Инкриментит каунтер в БД + /// + /// + /// + internal async Task FindOneAndUpdateRevisionAsync(string revisionName) + { + var result = await _storage.Revisions + .FindOneAndUpdateAsync( + r => r.Id == revisionName, + Builders.Update + .Inc(r => r.CurrentNumber, 1) + .SetOnInsert(r => r.Created, DateTime.UtcNow) + .Set(r => r.Updated, DateTime.UtcNow), + new FindOneAndUpdateOptions + { + IsUpsert = false, + ReturnDocument = ReturnDocument.After + }); + + return result; + } + + internal async Task AddDomainRevisionAsync(Revision revision) + { + await _storage.Revisions.InsertOneAsync(revision); + } + + + } +} diff --git a/BuildRevisionCounter.Core/Repositories/Impl/UserRepository.cs b/BuildRevisionCounter.Core/Repositories/Impl/UserRepository.cs new file mode 100644 index 0000000..22b7da1 --- /dev/null +++ b/BuildRevisionCounter.Core/Repositories/Impl/UserRepository.cs @@ -0,0 +1,59 @@ +using System.Threading.Tasks; +using BuildRevisionCounter.Core.Converters; +using BuildRevisionCounter.Core.DomainObjects; +using MongoDB.Driver; + + +namespace BuildRevisionCounter.Core.Repositories.Impl +{ + internal class UserRepository : IUserRepository + { + private readonly MongoContext _storage; + private readonly IUserConverter _userConverter; + + public UserRepository(IUserConverter userConverter) + { + _storage = MongoContext.Instance; + _userConverter = userConverter; + } + + #region IUserRepository + + public async Task GetUserByNameAsync(string userName) + { + var domainUser = await GetDomainUserByNameAsync(userName); + + if (domainUser == null) return null; + return _userConverter.ToProtocol(domainUser); + } + + public async Task CreateUserAsync(Protocol.User user) + { + var domainUser = _userConverter.ToDomain(user); + + await CreateDomainUserAsync(domainUser); + } + + public async Task CountAsync() + { + return await _storage.Users.CountAsync(_ => true); + } + + #endregion + + internal async Task GetDomainUserByNameAsync(string userName) + { + var user = await _storage.Users + .Find(u => u.Name == userName) + .FirstOrDefaultAsync(); + + return user; + } + + internal async Task CreateDomainUserAsync(User domainUser) + { + await _storage.Users.InsertOneAsync(domainUser); + } + + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Core/RepositoryFactory.cs b/BuildRevisionCounter.Core/RepositoryFactory.cs new file mode 100644 index 0000000..31c39c4 --- /dev/null +++ b/BuildRevisionCounter.Core/RepositoryFactory.cs @@ -0,0 +1,47 @@ +using System; +using BuildRevisionCounter.Core.Converters.Impl; +using BuildRevisionCounter.Core.Repositories; +using BuildRevisionCounter.Core.Repositories.Impl; + +namespace BuildRevisionCounter.Core +{ + public class RepositoryFactory + { + private static readonly Object SLock = new Object(); + private static volatile RepositoryFactory _instance = null; + + private RepositoryFactory() + { } + + public static RepositoryFactory Instance + { + get + { + if (_instance == null) + { + lock (SLock) + { + if (_instance == null) + _instance = new RepositoryFactory(); + } + } + return _instance; + } + } + + public IRevisionRepository GetRevisionRepository() + { + return new RevisionRepository(new RevisionConverter()); + } + + public IUserRepository GetUserRepository() + { + return new UserRepository(new UserConverter()); + } + + public IRepository GetRepository() + { + return MongoContext.Instance; + } + } +} \ No newline at end of file diff --git a/BuildRevisionCounter.Core/packages.config b/BuildRevisionCounter.Core/packages.config new file mode 100644 index 0000000..c276a7f --- /dev/null +++ b/BuildRevisionCounter.Core/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/BuildRevisionCounter.Tests/App.config b/BuildRevisionCounter.Tests/App.config index 1613985..948da8e 100644 --- a/BuildRevisionCounter.Tests/App.config +++ b/BuildRevisionCounter.Tests/App.config @@ -1,7 +1,7 @@  - + diff --git a/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj b/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj index 8ce0b45..9be19ea 100644 --- a/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj +++ b/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj @@ -92,15 +92,22 @@ - - + - + + {667844e5-6d11-474d-a18f-bc4784626f34} + BuildRevisionCounter.Protocol + + + {ddf51396-4ee1-45af-b134-ca1c56b0cd9f} + BuildRevisionCounter.Core + + {64eeea30-fce1-4aa6-a375-ebd721914708} - BuildRevisionCounter + BuildRevisionCounter.WebApi diff --git a/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs b/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs index c4bfe67..7682be8 100644 --- a/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs +++ b/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using System.Web.Http; using BuildRevisionCounter.Controllers; +using BuildRevisionCounter.Core; using NUnit.Framework; namespace BuildRevisionCounter.Tests.Controllers @@ -10,13 +11,21 @@ namespace BuildRevisionCounter.Tests.Controllers public class CounterControllerTest { private CounterController _controller; + private IRepository _repository; [TestFixtureSetUp] public void SetUp() { - MongoDBStorageUtils.SetUpAsync().Wait(); + SetUpAsync().Wait(); + } + + public async Task SetUpAsync() + { + _repository = RepositoryFactory.Instance.GetRepository(); + await _repository.DropDatabaseAsync(); + await _repository.SetUpAsync(); - _controller = new CounterController(MongoDBStorageFactory.DefaultInstance); + _controller = new CounterController(); } [Test] diff --git a/BuildRevisionCounter.Tests/IntegrationTest/IntegrationTest.cs b/BuildRevisionCounter.Tests/IntegrationTest/IntegrationTest.cs index 08658a6..e3ba98b 100644 --- a/BuildRevisionCounter.Tests/IntegrationTest/IntegrationTest.cs +++ b/BuildRevisionCounter.Tests/IntegrationTest/IntegrationTest.cs @@ -6,6 +6,7 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using BuildRevisionCounter.Core; using Microsoft.Owin.Hosting; using NUnit.Framework; @@ -27,7 +28,15 @@ public void Setup() _uri = string.Format("http://localhost:{0}", port); _application = WebApp.Start(_uri); - MongoDBStorageUtils.SetUpAsync().Wait(); + SetUpAsync().Wait(); + } + + public async Task SetUpAsync() + { + await MongoContext.Instance.Client.DropDatabaseAsync( + MongoContext.Instance.Database.DatabaseNamespace.DatabaseName); + + await MongoContext.Instance.SetUpAsync(); } diff --git a/BuildRevisionCounter.Tests/MongoDBStorageTest.cs b/BuildRevisionCounter.Tests/MongoDBStorageTest.cs index c498db1..e4deb6e 100644 --- a/BuildRevisionCounter.Tests/MongoDBStorageTest.cs +++ b/BuildRevisionCounter.Tests/MongoDBStorageTest.cs @@ -1,4 +1,8 @@ using System.Threading.Tasks; +using BuildRevisionCounter.Core; +using BuildRevisionCounter.Core.Converters.Impl; +using BuildRevisionCounter.Core.Repositories.Impl; +using BuildRevisionCounter.Protocol; using MongoDB.Driver; using NUnit.Framework; @@ -7,73 +11,82 @@ namespace BuildRevisionCounter.Tests [TestFixture] public class MongoDBStorageTest { - private MongoDBStorage _storage; + private UserRepository _userRepository; [TestFixtureSetUp] public void SetUp() { + _userRepository = new UserRepository(new UserConverter()); SetUpAsync().Wait(); } public async Task SetUpAsync() { - _storage = MongoDBStorageFactory.DefaultInstance; + await MongoContext.Instance.Client.DropDatabaseAsync( + MongoContext.Instance.Database.DatabaseNamespace.DatabaseName); - await _storage.Revisions.Database.Client.DropDatabaseAsync( - _storage.Revisions.Database.DatabaseNamespace.DatabaseName); - - await _storage.SetUp(); + await MongoContext.Instance.SetUpAsync(); } [Test] public async Task EnsureAdminUserCreated() { - var user = await _storage.FindUser(MongoDBStorage.AdminName); - Assert.AreEqual(MongoDBStorage.AdminName, user.Name); + var user = await _userRepository.GetUserByNameAsync(MongoContext.AdminName); + Assert.AreEqual(MongoContext.AdminName, user.Name); } [Test] public async Task CreateUser() { - await _storage.CreateUser("test", "test", new[] {"testRole"}); + await _userRepository.CreateUserAsync(new User { Name = "test", Password = "test", Roles = new[] { "testRole" } }); } [Test] public async Task FindUserReturnsNullIfNoUserFound() { - var user = await _storage.FindUser("FindUserReturnsNullIfNoUserFound"); + var user = await _userRepository.GetUserByNameAsync("FindUserReturnsNullIfNoUserFound"); Assert.IsNull(user); } [Test] public async Task FindUserReturnsCreatedUser() { - await _storage.CreateUser("FindUserReturnsCreatedUser", "FindUserReturnsCreatedUser", new[] {"testRole"}); - var user = await _storage.FindUser("FindUserReturnsCreatedUser"); + await + _userRepository.CreateUserAsync(new User + { + Name = "FindUserReturnsCreatedUser", + Password = "FindUserReturnsCreatedUser", + Roles = new[] { "testRole" } + }); + var user = await _userRepository.GetUserByNameAsync("FindUserReturnsCreatedUser"); Assert.AreEqual("FindUserReturnsCreatedUser", user.Name); } [Test] public async Task EnsureAdminUserMayBeInvokedMultipleTimes() { - await _storage.EnsureAdminUser(); - await _storage.EnsureAdminUser(); + await MongoContext.Instance.EnsureAdminUser(); + await MongoContext.Instance.EnsureAdminUser(); } [Test] public async Task CreateUserMustThrowExceptionIfUserExists() { - await _storage.CreateUser( - "CreateUserMustThrowExceptionIfUserExists", - "CreateUserMustThrowExceptionIfUserExists", - new[] {"testRole"}); + await _userRepository.CreateUserAsync(new User + { + Name = "CreateUserMustThrowExceptionIfUserExists", + Password = "CreateUserMustThrowExceptionIfUserExists", + Roles = new[] { "testRole" } + }); try { - await _storage.CreateUser( - "CreateUserMustThrowExceptionIfUserExists", - "CreateUserMustThrowExceptionIfUserExists", - new[] {"testRole"}); + await _userRepository.CreateUserAsync(new User + { + Name = "CreateUserMustThrowExceptionIfUserExists", + Password = "CreateUserMustThrowExceptionIfUserExists", + Roles = new[] { "testRole" } + }); Assert.Fail(); } catch (MongoWriteException ex) diff --git a/BuildRevisionCounter.Tests/Repositories/RevisionRepositoryTest.cs b/BuildRevisionCounter.Tests/Repositories/RevisionRepositoryTest.cs new file mode 100644 index 0000000..c780008 --- /dev/null +++ b/BuildRevisionCounter.Tests/Repositories/RevisionRepositoryTest.cs @@ -0,0 +1,73 @@ +using System.Threading.Tasks; +using BuildRevisionCounter.Core.Converters.Impl; +using BuildRevisionCounter.Core.DomainObjects; +using BuildRevisionCounter.Core.Repositories.Impl; +using NUnit.Framework; + +namespace BuildRevisionCounter.Tests.Repositories +{ + [TestFixture] + public class RevisionRepositoryTest + { + private RevisionRepository _repository; + + [TestFixtureSetUp] + public void ClassSetUp() + { + _repository = new RevisionRepository(new RevisionConverter()); + } + + [SetUp] + public void TestSetUp() + { + _repository.ClearRevisionCollectionAsync().Wait(); + } + + [Test] + public async Task GetDomainRevisionByIdAsync_WhenIdNotExists_ReturnNull() + { + var revision = await _repository.GetDomainRevisionByIdAsync("unknownRev"); + + Assert.IsNull(revision); + } + + [Test] + public async Task GetDomainRevisionByIdAsync_WhenIdExists_ReturnRevision() + { + const string expectedRevId = "testRev"; + var expectedRev = new Revision {Id = expectedRevId}; + await _repository.AddDomainRevisionAsync(expectedRev); + + var actualRev = await _repository.GetDomainRevisionByIdAsync(expectedRevId); + var actualRevId = actualRev.Id; + + Assert.AreEqual(expectedRevId, actualRevId); + } + + [Test] + public async Task IncrementDomainRevisionAsync_WhenNotExist_CreateWithNumberZero() + { + const int expectedNextNumber = 0; + const string revId = "testRev"; + + var newRevision = await _repository.IncrementDomainRevisionAsync(revId); + var actualNextNumber = newRevision.CurrentNumber; + + Assert.AreEqual(expectedNextNumber, actualNextNumber); + } + + [Test] + public async Task IncrementDomainRevisionAsync_WhenExist_IncrementNumber() + { + const string revId = "testRev"; + const int expectedNextNumber = 4; + var expectedRev = new Revision {Id = revId, CurrentNumber = expectedNextNumber - 1}; + await _repository.AddDomainRevisionAsync(expectedRev); + + var actualRev = await _repository.IncrementDomainRevisionAsync(revId); + var actualNextNumber = actualRev.CurrentNumber; + + Assert.AreEqual(expectedNextNumber, actualNextNumber); + } + } +} diff --git a/BuildRevisionCounter.sln b/BuildRevisionCounter.sln index e504ccf..298ec45 100644 --- a/BuildRevisionCounter.sln +++ b/BuildRevisionCounter.sln @@ -3,10 +3,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter", "BuildRevisionCounter\BuildRevisionCounter.csproj", "{64EEEA30-FCE1-4AA6-A375-EBD721914708}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter.WebApi", "BuildRevisionCounter\BuildRevisionCounter.WebApi.csproj", "{64EEEA30-FCE1-4AA6-A375-EBD721914708}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter.Tests", "BuildRevisionCounter.Tests\BuildRevisionCounter.Tests.csproj", "{837D9E7D-D0CC-4924-85B5-916FC5D931BA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter.Protocol", "BuildRevisionCounter.Contract\BuildRevisionCounter.Protocol.csproj", "{667844E5-6D11-474D-A18F-BC4784626F34}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter.Core", "BuildRevisionCounter.Core\BuildRevisionCounter.Core.csproj", "{DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +25,14 @@ Global {837D9E7D-D0CC-4924-85B5-916FC5D931BA}.Debug|Any CPU.Build.0 = Debug|Any CPU {837D9E7D-D0CC-4924-85B5-916FC5D931BA}.Release|Any CPU.ActiveCfg = Release|Any CPU {837D9E7D-D0CC-4924-85B5-916FC5D931BA}.Release|Any CPU.Build.0 = Release|Any CPU + {667844E5-6D11-474D-A18F-BC4784626F34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {667844E5-6D11-474D-A18F-BC4784626F34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {667844E5-6D11-474D-A18F-BC4784626F34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {667844E5-6D11-474D-A18F-BC4784626F34}.Release|Any CPU.Build.0 = Release|Any CPU + {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BuildRevisionCounter/BuildRevisionCounter.csproj b/BuildRevisionCounter/BuildRevisionCounter.WebApi.csproj similarity index 92% rename from BuildRevisionCounter/BuildRevisionCounter.csproj rename to BuildRevisionCounter/BuildRevisionCounter.WebApi.csproj index 596f9ab..76352fa 100644 --- a/BuildRevisionCounter/BuildRevisionCounter.csproj +++ b/BuildRevisionCounter/BuildRevisionCounter.WebApi.csproj @@ -120,10 +120,6 @@ - - - - @@ -136,6 +132,19 @@ Designer + + + {667844e5-6d11-474d-a18f-bc4784626f34} + BuildRevisionCounter.Protocol + + + {ddf51396-4ee1-45af-b134-ca1c56b0cd9f} + BuildRevisionCounter.Core + + + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/BuildRevisionCounter/Controllers/CounterController.cs b/BuildRevisionCounter/Controllers/CounterController.cs index ae9e355..8ed764a 100644 --- a/BuildRevisionCounter/Controllers/CounterController.cs +++ b/BuildRevisionCounter/Controllers/CounterController.cs @@ -3,10 +3,9 @@ using System.Net; using System.Threading.Tasks; using System.Web.Http; -using BuildRevisionCounter.Interfaces; -using BuildRevisionCounter.Model; +using BuildRevisionCounter.Core; +using BuildRevisionCounter.Protocol; using BuildRevisionCounter.Security; -using MongoDB.Driver; namespace BuildRevisionCounter.Controllers { @@ -14,33 +13,16 @@ namespace BuildRevisionCounter.Controllers [BasicAuthentication] public class CounterController : ApiController { - private readonly IMongoDBStorage _mongoDbStorage; - - /// - /// Конструктор контроллера номеров ревизий. - /// - /// Объект для получения данных из БД Монго. - public CounterController(IMongoDBStorage mongoDbStorage) - { - if (mongoDbStorage == null) - throw new ArgumentNullException("mongoDbStorage"); - - _mongoDbStorage = mongoDbStorage; - } - [HttpGet] [Route("")] [Authorize(Roles = "admin, editor, anonymous")] - public async Task> GetAllRevision([FromUri] Int32 pageSize = 20, [FromUri] Int32 pageNumber = 1) + public async Task> GetAllRevision([FromUri] Int32 pageSize = 20, [FromUri] Int32 pageNumber = 1) { if (pageSize < 1 || pageNumber < 1) throw new HttpResponseException(HttpStatusCode.BadRequest); - var revisions = await _mongoDbStorage.Revisions - .Find(r => true) - .Skip(pageSize * (pageNumber - 1)) - .Limit(pageSize) - .ToListAsync(); + var repository = RepositoryFactory.Instance.GetRevisionRepository(); + var revisions = await repository.GetAllRevisionAsync(pageSize, pageNumber); if (revisions == null) throw new HttpResponseException(HttpStatusCode.NotFound); @@ -53,9 +35,8 @@ public async Task> GetAllRevision([FromUri] I [Authorize(Roles = "admin, editor, anonymous")] public async Task Current([FromUri] string revisionName) { - var revision = await _mongoDbStorage.Revisions - .Find(r => r.Id == revisionName) - .SingleOrDefaultAsync(); + var repository = RepositoryFactory.Instance.GetRevisionRepository(); + var revision = await repository.GetRevisionByIdAsync(revisionName); if (revision == null) throw new HttpResponseException(HttpStatusCode.NotFound); @@ -68,58 +49,13 @@ public async Task Current([FromUri] string revisionName) [Authorize(Roles = "buildserver")] public async Task Bumping([FromUri] string revisionName) { - // попробуем обновить документ - var result = await FindOneAndUpdateRevisionModelAsync(revisionName); - if (result != null) - return result.CurrentNumber; - - // если не получилось, значит документ еще не был создан - // создадим его с начальным значением 0 - try - { - await _mongoDbStorage.Revisions - .InsertOneAsync(new RevisionModel - { - Id = revisionName, - CurrentNumber = 0, - Created = DateTime.UtcNow - }); - return 0; - } - catch (MongoWriteException ex) - { - if (ex.WriteError.Category != ServerErrorCategory.DuplicateKey) - throw; - } - - // если при вставке произошла ошибка значит мы не успели и запись там уже есть - // и теперь попытка обновления должна пройти без ошибок - result = await FindOneAndUpdateRevisionModelAsync(revisionName); + var repository = RepositoryFactory.Instance.GetRevisionRepository(); + var revision = await repository.IncrementRevisionAsync(revisionName); - return result.CurrentNumber; - } - - /// - /// Инкриментит каунтер в БД - /// - /// - /// - private async Task FindOneAndUpdateRevisionModelAsync(string revisionName) - { - var result = await _mongoDbStorage.Revisions - .FindOneAndUpdateAsync( - r => r.Id == revisionName, - Builders.Update - .Inc(r => r.CurrentNumber, 1) - .SetOnInsert(r => r.Created, DateTime.UtcNow) - .Set(r => r.Updated, DateTime.UtcNow), - new FindOneAndUpdateOptions - { - IsUpsert = false, - ReturnDocument = ReturnDocument.After - }); + if (revision == null) + throw new HttpResponseException(HttpStatusCode.NotFound); - return result; + return revision.CurrentNumber; } } } \ No newline at end of file diff --git a/BuildRevisionCounter/Interfaces/IMongoDBStorage.cs b/BuildRevisionCounter/Interfaces/IMongoDBStorage.cs deleted file mode 100644 index c75dc23..0000000 --- a/BuildRevisionCounter/Interfaces/IMongoDBStorage.cs +++ /dev/null @@ -1,21 +0,0 @@ -using BuildRevisionCounter.Model; -using MongoDB.Driver; - -namespace BuildRevisionCounter.Interfaces -{ - /// - /// Интерфейс для получения данных из БД Монго. - /// - public interface IMongoDBStorage - { - /// - /// MongoDB-коллекция ревизий. - /// - IMongoCollection Revisions { get; } - - /// - /// MongoDB-коллекция пользователей. - /// - IMongoCollection Users { get; } - } -} \ No newline at end of file diff --git a/BuildRevisionCounter/Model/RevisionModel.cs b/BuildRevisionCounter/Model/RevisionModel.cs deleted file mode 100644 index 96adbbd..0000000 --- a/BuildRevisionCounter/Model/RevisionModel.cs +++ /dev/null @@ -1,24 +0,0 @@ -using MongoDB.Bson.Serialization.Attributes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace BuildRevisionCounter.Model -{ - public class RevisionModel - { - [BsonId] - public string Id; - - [BsonElement("created"), BsonDateTimeOptions(Kind=DateTimeKind.Utc)] - public DateTime Created; - - [BsonElement("updated"), BsonDateTimeOptions(Kind = DateTimeKind.Utc)] - public DateTime Updated; - - [BsonElement("currentNumber")] - public long CurrentNumber; - - } -} \ No newline at end of file diff --git a/BuildRevisionCounter/MongoDBStorage.cs b/BuildRevisionCounter/MongoDBStorage.cs deleted file mode 100644 index f5d9c84..0000000 --- a/BuildRevisionCounter/MongoDBStorage.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Threading.Tasks; -using BuildRevisionCounter.Interfaces; -using BuildRevisionCounter.Model; -using MongoDB.Driver; - -namespace BuildRevisionCounter -{ - public class MongoDBStorage : IMongoDBStorage - { - public static readonly string AdminName = "admin"; - public static readonly string AdminPassword = "admin"; - public static readonly string[] AdminRoles = {"admin", "buildserver", "editor"}; - - public IMongoCollection Revisions { get; private set; } - public IMongoCollection Users { get; private set; } - - public MongoDBStorage(IMongoDatabase database) - { - Revisions = database.GetCollection("revisions"); - Users = database.GetCollection("users"); - - Task.Run(() => SetUp()).Wait(); - } - - public async Task SetUp() - { - await EnsureUsersIndex(); - await EnsureAdminUser(); - } - - public async Task EnsureUsersIndex() - { - await Users.Indexes.CreateOneAsync( - Builders.IndexKeys.Ascending(u => u.Name), - new CreateIndexOptions { Unique = true, }); - } - - public async Task EnsureAdminUser() - { - if (await Users.CountAsync(_ => true) == 0) - { - await CreateUser(AdminName, AdminPassword, AdminRoles); - } - } - - public async Task FindUser(string name) - { - return await Users.Find(u => u.Name == name).SingleOrDefaultAsync(); - } - - public Task CreateUser(string name, string password, string[] roles) - { - return Users - .InsertOneAsync( - new UserModel - { - Name = name, - Password = password, - Roles = roles - }); - } - } -} \ No newline at end of file diff --git a/BuildRevisionCounter/Properties/PublishProfiles/ToFileSystem.pubxml b/BuildRevisionCounter/Properties/PublishProfiles/ToFileSystem.pubxml index e872f41..d1195c2 100644 --- a/BuildRevisionCounter/Properties/PublishProfiles/ToFileSystem.pubxml +++ b/BuildRevisionCounter/Properties/PublishProfiles/ToFileSystem.pubxml @@ -5,13 +5,13 @@ by editing this MSBuild file. In order to learn more about this please visit htt --> - FileSystem - Release - Any CPU - - True - True - $(MSBuildThisFileDirectory)..\..\..\publish - True +FileSystem +Release +Any CPU + +True +True +$(MSBuildThisFileDirectory)..\..\..\publish +True \ No newline at end of file diff --git a/BuildRevisionCounter/Security/BasicAuthenticationFilter.cs b/BuildRevisionCounter/Security/BasicAuthenticationFilter.cs index e8a5228..0b4e977 100644 --- a/BuildRevisionCounter/Security/BasicAuthenticationFilter.cs +++ b/BuildRevisionCounter/Security/BasicAuthenticationFilter.cs @@ -6,9 +6,7 @@ using System.Threading; using System.Threading.Tasks; using System.Web.Http.Filters; -using BuildRevisionCounter.Interfaces; -using BuildRevisionCounter.Model; -using MongoDB.Driver; +using BuildRevisionCounter.Core; namespace BuildRevisionCounter.Security { @@ -28,21 +26,7 @@ public class BasicAuthenticationFilter : IAuthenticationFilter Encoding.ASCII.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback); - - private readonly IMongoDBStorage _mongoDbStorage; - - /// - /// Конструктор фильтра. - /// - /// Объект для получения данных из БД Монго. - public BasicAuthenticationFilter(IMongoDBStorage mongoDbStorage) - { - if (mongoDbStorage == null) - throw new ArgumentNullException("mongoDbStorage"); - - _mongoDbStorage = mongoDbStorage; - } - + public string Realm { get; set; } #region IAuthenticationFilter Members @@ -88,11 +72,10 @@ public Task ChallengeAsync(HttpAuthenticationChallengeContext context, Cancellat private async Task Authenticate(string userName, string password) { + var repository = RepositoryFactory.Instance.GetUserRepository(); + IPrincipal principal = null; - var user = - await - _mongoDbStorage.Users.Find(Builders.Filter.Where(u => u.Name == userName)) - .SingleOrDefaultAsync(); + var user = await repository.GetUserByNameAsync(userName); if (user != null && user.Password == password) { principal = new GenericPrincipal(new GenericIdentity(userName), user.Roles); diff --git a/BuildRevisionCounter/Startup.cs b/BuildRevisionCounter/Startup.cs index fc77cfa..2240f31 100644 --- a/BuildRevisionCounter/Startup.cs +++ b/BuildRevisionCounter/Startup.cs @@ -1,8 +1,6 @@ -using System.Configuration; -using System.Web.Http.Filters; +using System.Web.Http.Filters; using BuildRevisionCounter.Security; using Microsoft.Owin; -using MongoDB.Driver; using Ninject; using Ninject.Web.Common.OwinHost; using Ninject.Web.WebApi.FilterBindingSyntax; @@ -11,7 +9,6 @@ using BuildRevisionCounter; using System.Web.Http; using System.Net.Http.Formatting; -using BuildRevisionCounter.Interfaces; [assembly: OwinStartup(typeof(Startup))] @@ -58,16 +55,7 @@ private static IKernel CreateKernel() /// Ядро Ninject. private static void RegisterServices(IKernel kernel) { - kernel.Bind().ToMethod(c => GetMongoDbStorage()).InSingletonScope(); kernel.BindHttpFilter(FilterScope.Controller).WhenControllerHas(); } - - private static MongoDBStorage GetMongoDbStorage(string connectionStringName = "MongoDBStorage") - { - var connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString; - var mongoUrl = MongoUrl.Create(connectionString); - var database = new MongoClient(mongoUrl).GetDatabase(mongoUrl.DatabaseName); - return new MongoDBStorage(database); - } } } diff --git a/BuildRevisionCounter/Web.config b/BuildRevisionCounter/Web.config index 210bf89..f6375ed 100644 --- a/BuildRevisionCounter/Web.config +++ b/BuildRevisionCounter/Web.config @@ -1,26 +1,26 @@  - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file