diff --git a/BSN.Commons.sln b/BSN.Commons.sln
index dffa831..1ceccb8 100644
--- a/BSN.Commons.sln
+++ b/BSN.Commons.sln
@@ -43,9 +43,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BSN.Commons.Orm.EntityFrame
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BSN.Commons.Users", "Source\BSN.Commons.Users\BSN.Commons.Users.csproj", "{213ABCEF-7E9A-4CE5-A3EF-289C9781344D}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BSN.Commons.Orm.Redis", "Source\BSN.Commons.Orm.Redis\BSN.Commons.Orm.Redis.csproj", "{1A1586E8-46EB-43AC-91EC-F6EDCA5689A9}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BSN.Commons.Orm.Redis", "Source\BSN.Commons.Orm.Redis\BSN.Commons.Orm.Redis.csproj", "{1A1586E8-46EB-43AC-91EC-F6EDCA5689A9}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BSN.Commons.Orm.Redis.Tests", "Test\BSN.Commons.Orm.Redis.Tests\BSN.Commons.Orm.Redis.Tests.csproj", "{2D1DB295-5181-48D7-8EC0-1147ED2DAD4A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BSN.Commons.Orm.Redis.Tests", "Test\BSN.Commons.Orm.Redis.Tests\BSN.Commons.Orm.Redis.Tests.csproj", "{2D1DB295-5181-48D7-8EC0-1147ED2DAD4A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BSN.Commons.AutoMapper", "Source\BSN.Commons.AutoMapper\BSN.Commons.AutoMapper.csproj", "{279E7016-E2E9-430E-82A3-C9037FE0E08E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BSN.Commons.AutoMapper.Tests", "Test\BSN.Commons.AutoMapper.Tests\BSN.Commons.AutoMapper.Tests.csproj", "{E8077467-8559-4669-B9FA-22530F1411E1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -93,6 +97,14 @@ Global
{2D1DB295-5181-48D7-8EC0-1147ED2DAD4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D1DB295-5181-48D7-8EC0-1147ED2DAD4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D1DB295-5181-48D7-8EC0-1147ED2DAD4A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {279E7016-E2E9-430E-82A3-C9037FE0E08E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {279E7016-E2E9-430E-82A3-C9037FE0E08E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {279E7016-E2E9-430E-82A3-C9037FE0E08E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {279E7016-E2E9-430E-82A3-C9037FE0E08E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E8077467-8559-4669-B9FA-22530F1411E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E8077467-8559-4669-B9FA-22530F1411E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E8077467-8559-4669-B9FA-22530F1411E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E8077467-8559-4669-B9FA-22530F1411E1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -108,6 +120,8 @@ Global
{213ABCEF-7E9A-4CE5-A3EF-289C9781344D} = {DC377ADC-CC9D-4785-81BE-726DBF5F3096}
{1A1586E8-46EB-43AC-91EC-F6EDCA5689A9} = {DC377ADC-CC9D-4785-81BE-726DBF5F3096}
{2D1DB295-5181-48D7-8EC0-1147ED2DAD4A} = {5C6BA7B5-832A-495A-AF5E-C2A74F6A1EF9}
+ {279E7016-E2E9-430E-82A3-C9037FE0E08E} = {DC377ADC-CC9D-4785-81BE-726DBF5F3096}
+ {E8077467-8559-4669-B9FA-22530F1411E1} = {5C6BA7B5-832A-495A-AF5E-C2A74F6A1EF9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BCAF76D3-AA3C-4D0F-8D10-34065F8FED09}
diff --git a/Build/build.cake b/Build/build.cake
index 149665a..2737a44 100644
--- a/Build/build.cake
+++ b/Build/build.cake
@@ -21,10 +21,11 @@ var projects = new List<(string path, string name, string version)>
{
("BSN.Commons/", "BSN.Commons.csproj", solutionVersion),
("BSN.Commons.Users/", "BSN.Commons.Users.csproj", solutionVersion),
- ("BSN.Commons.PresentationInfrastructure/", "BSN.Commons.PresentationInfrastructure.csproj", solutionVersion),
+ ("BSN.Commons.Orm.Redis/", "BSN.Commons.Orm.Redis.csproj", solutionVersion),
+ ("BSN.Commons.AutoMapper/", "BSN.Commons.AutoMapper.csproj", solutionVersion),
("BSN.Commons.Orm.EntityFramework/", "BSN.Commons.Orm.EntityFramework.csproj", solutionVersion),
("BSN.Commons.Orm.EntityFrameworkCore/", "BSN.Commons.Orm.EntityFrameworkCore.csproj", solutionVersion),
- ("BSN.Commons.Orm.Redis/", "BSN.Commons.Orm.Redis.csproj", solutionVersion)
+ ("BSN.Commons.PresentationInfrastructure/", "BSN.Commons.PresentationInfrastructure.csproj", solutionVersion)
};
var mainProject = "../Source/BSN.Commons/BSN.Commons.csproj";
@@ -35,7 +36,8 @@ var testProjects = new List<(string path, string name, string dll)>
("BSN.Commons.Tests/", "BSN.Commons.Tests.csproj", "bin/Release/net472/BSN.Commons.Tests.dll"),
("BSN.Commons.Orm.EntityFramework.Tests/", "BSN.Commons.Orm.EntityFramework.Tests.csproj", "bin/Release/net48/BSN.Commons.Orm.EntityFramework.Tests.dll"),
("BSN.Commons.Orm.EntityFrameworkCore.Tests/", "BSN.Commons.Orm.EntityFrameworkCore.Tests.csproj", "bin/Release/netcoreapp3.1/BSN.Commons.Orm.EntityFrameworkCore.Tests.dll"),
- ("BSN.Commons.Orm.Redis.Tests/", "BSN.Commons.Orm.Redis.Tests.csproj", "bin/Release/net8.0/BSN.Commons.Orm.Redis.Tests.dll")
+ ("BSN.Commons.Orm.Redis.Tests/", "BSN.Commons.Orm.Redis.Tests.csproj", "bin/Release/net8.0/BSN.Commons.Orm.Redis.Tests.dll"),
+ ("BSN.Commons.AutoMapper.Tests/", "BSN.Commons.AutoMapper.Tests.csproj", "bin/Release/net8.0/BSN.Commons.AutoMapper.Tests.dll")
};
var coverageResultsFileName = "coverage.xml";
var testResultsFileName = "nunitResults.xml";
diff --git a/Source/BSN.Commons.AutoMapper/BSN.Commons.AutoMapper.csproj b/Source/BSN.Commons.AutoMapper/BSN.Commons.AutoMapper.csproj
new file mode 100644
index 0000000..caf4d84
--- /dev/null
+++ b/Source/BSN.Commons.AutoMapper/BSN.Commons.AutoMapper.csproj
@@ -0,0 +1,47 @@
+
+
+
+ net8.0
+ 1.15.0
+ 1.15.0
+ BSN Developers
+ BSN Company
+ AutoMapper Helpers for using AutoMapper in enterprise application.
+ BSN Co 2019-2024
+ MIT
+ https://github.com/BSVN/Commons
+ https://github.com/BSVN/Commons.git
+ git
+ Please see CHANGELOG.md
+ 1.15.0
+ True
+ True
+ BSN.Commons.AutoMapper
+ README.md
+ True
+ snupkg
+ BSN.jpg
+ BSN;Commons;AutoMapper
+
+ true
+
+ true
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/BSN.Commons.AutoMapper/CHANGELOG.md b/Source/BSN.Commons.AutoMapper/CHANGELOG.md
new file mode 100644
index 0000000..05d22aa
--- /dev/null
+++ b/Source/BSN.Commons.AutoMapper/CHANGELOG.md
@@ -0,0 +1,20 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [1.15.0] - 2024-06-29
+Fixed issue with mapping between domain and view models.
+
+### Added
+- README.md and CHANGELOG.md
+- Added support for AutoMapper 13.0.1
+- Added predefined conversions for mapping `BSN.Commons.PresentationInfrastructure` Models.
+
+### Fixed
+- Resolve some missing elements in nupkg.
+
+### Changed
+- Update documentation.
\ No newline at end of file
diff --git a/Source/BSN.Commons.AutoMapper/CommonsMappingProfile.cs b/Source/BSN.Commons.AutoMapper/CommonsMappingProfile.cs
new file mode 100644
index 0000000..09209bd
--- /dev/null
+++ b/Source/BSN.Commons.AutoMapper/CommonsMappingProfile.cs
@@ -0,0 +1,40 @@
+using AutoMapper;
+using BSN.Commons.Responses;
+
+namespace BSN.Commons.AutoMapper
+{
+ public class CommonMapperProfile : Profile
+ {
+ public CommonMapperProfile()
+ {
+ CreateMap(typeof(PagedEntityCollection<>), typeof(PaginationMetadata)).ConvertUsing(typeof(PagedEntityCollectionToMetaDataConverter<>));
+
+ CreateMap(typeof(IEnumerable<>), typeof(CollectionViewModel<>)).ConvertUsing(typeof(GenericIEnumerableToCollectionViewModelConverter<,>));
+ }
+
+ private class PagedEntityCollectionToMetaDataConverter : ITypeConverter, PaginationMetadata>
+ {
+ public PaginationMetadata Convert(PagedEntityCollection source, PaginationMetadata destination, ResolutionContext context)
+ {
+ return new PaginationMetadata()
+ {
+ Page = source.CurrentPage,
+ PageCount = source.PageSize,
+ PageSize = source.PageSize,
+ RecordCount = source.RecordCount
+ };
+ }
+ }
+
+ private class GenericIEnumerableToCollectionViewModelConverter : ITypeConverter, CollectionViewModel>
+ {
+ public CollectionViewModel Convert(IEnumerable source, CollectionViewModel destination, ResolutionContext context)
+ {
+ return new CollectionViewModel
+ {
+ Items = context.Mapper.Map>(source)
+ };
+ }
+ }
+ }
+}
diff --git a/Source/BSN.Commons.AutoMapper/Extensions/IServiceCollectionExtensions.cs b/Source/BSN.Commons.AutoMapper/Extensions/IServiceCollectionExtensions.cs
new file mode 100644
index 0000000..b70d44c
--- /dev/null
+++ b/Source/BSN.Commons.AutoMapper/Extensions/IServiceCollectionExtensions.cs
@@ -0,0 +1,27 @@
+using AutoMapper;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace BSN.Commons.AutoMapper.Extensions
+{
+ public static class IServiceCollectionExtensions
+ {
+ public static IServiceCollection AddAutoMapper(this IServiceCollection services, Action configure)
+ {
+ var mappingConfig = new MapperConfiguration(config =>
+ {
+ MapperConfigurationExpression mapperConfigurationExpression = new MapperConfigurationExpression();
+ configure(mapperConfigurationExpression);
+
+ configure(config);
+
+ config.AddProfile(new CommonMapperProfile());
+ });
+
+ IMapper mapper = mappingConfig.CreateMapper();
+
+ services.AddSingleton(mapper);
+
+ return services;
+ }
+ }
+}
diff --git a/Source/BSN.Commons.AutoMapper/README.md b/Source/BSN.Commons.AutoMapper/README.md
new file mode 100644
index 0000000..7310d6f
--- /dev/null
+++ b/Source/BSN.Commons.AutoMapper/README.md
@@ -0,0 +1,59 @@
+# BSN.Commons.AutoMapper
+
+This package contains some facilities for using AutoMapper in Enterprise Applications.
+
+AutoMapper is a popular library for mapping objects from one Model to Another. It simplifies the process of mapping complex objects and reduces the amount of code needed to perform these mappings stuffs.
+
+**BSN.Commons.Automapper** is a package that provides some predefined mappings for **BSN.Commons.PresentationInfrastructure** Models.
+This helps **BSN.Commons** users to skip writing required mapping to dealing with these Models.
+
+### 1. Installation
+To use this package, you need to first install it on your web api or presentation layer. You can do this by running the following command (in package manager console):
+```
+Install-Package BSN.Commons.AutoMapper
+```
+
+### 2. Add Your required mapping profiles
+To use these predefined mapping profiles and injecting your preferred profiles you just need to add following line in the `ServiceCollection`:
+```
+services.AddAutoMapper(config => config.AddProfile());
+```
+or
+```
+services.AddAutoMapper(config =>
+{
+ config.AddProfile();
+ config.AddProfile();
+});
+```
+
+### 3. Predefined mapping profile:
+
+Provided built in mapping profile contains following mappings:
+
+#### PagedEntityCollectionToMetaDataConverter:
+A default converter which converts `PagedEntityCollection` to `PaginationMetadata`.
+#### GenericIEnumerableToCollectionViewModelConverter:
+A generic default converter which converts `IEnumerable` to `CollectionViewModel`
+
+### 4. Example Usage
+
+#### PagedEntityCollectionToMetaDataConverter
+```
+var pagedEntities = new PagedEntityCollection(products, 1, 10, 100);
+var paginationMetadata = mapper.Map(pagedEntities);
+```
+
+#### GenericIEnumerableToCollectionViewModelConverter
+```
+var products = new List
+{
+ new Product { Id = 1, Name = "Product 1" },
+ new Product { Id = 2, Name = "Product 2" },
+ new Product { Id = 3, Name = "Product 3" }
+};
+
+var collectionViewModel = mapper.Map>(products);
+```
+
+`BSN.Commons.AutoMapper` is Copyright © 2024 BSN and other contributors under the BSN license.
\ No newline at end of file
diff --git a/Test/BSN.Commons.AutoMapper.Tests/AutoMapperTestBase.cs b/Test/BSN.Commons.AutoMapper.Tests/AutoMapperTestBase.cs
new file mode 100644
index 0000000..6291ca6
--- /dev/null
+++ b/Test/BSN.Commons.AutoMapper.Tests/AutoMapperTestBase.cs
@@ -0,0 +1,19 @@
+using AutoMapper;
+
+namespace BSN.Commons.AutoMapper.Tests
+{
+ public abstract class AutoMapperTestBase
+ {
+ protected readonly IMapper _mapper;
+
+ protected AutoMapperTestBase()
+ {
+ var configuration = new MapperConfiguration(cfg =>
+ {
+ cfg.AddProfile();
+ });
+
+ _mapper = configuration.CreateMapper();
+ }
+ }
+}
diff --git a/Test/BSN.Commons.AutoMapper.Tests/BSN.Commons.AutoMapper.Tests.csproj b/Test/BSN.Commons.AutoMapper.Tests/BSN.Commons.AutoMapper.Tests.csproj
new file mode 100644
index 0000000..42189c4
--- /dev/null
+++ b/Test/BSN.Commons.AutoMapper.Tests/BSN.Commons.AutoMapper.Tests.csproj
@@ -0,0 +1,33 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Test/BSN.Commons.AutoMapper.Tests/CommonMapperProfileTests.cs b/Test/BSN.Commons.AutoMapper.Tests/CommonMapperProfileTests.cs
new file mode 100644
index 0000000..02ccf91
--- /dev/null
+++ b/Test/BSN.Commons.AutoMapper.Tests/CommonMapperProfileTests.cs
@@ -0,0 +1,94 @@
+using AutoMapper;
+using BSN.Commons.Responses;
+
+namespace BSN.Commons.AutoMapper.Tests
+{
+ [TestFixture]
+ public class CommonMapperProfileTests
+ {
+ [Test]
+ public void PagedEntityCollectionToMetaDataConverter_ConvertsCorrectly()
+ {
+ // Arrange
+ var profile = new CommonMapperProfile();
+ var configuration = new MapperConfiguration(cfg => cfg.AddProfile(profile));
+ var mapper = new Mapper(configuration);
+ var pagedEntityCollection = new PagedEntityCollection
+ {
+ CurrentPage = 1,
+ PageSize = 10,
+ RecordCount = 100
+ };
+
+ // Act
+ var result = mapper.Map(pagedEntityCollection);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.AreEqual(pagedEntityCollection.CurrentPage, result.Page);
+ Assert.AreEqual(pagedEntityCollection.PageSize, result.PageSize);
+ Assert.AreEqual(pagedEntityCollection.RecordCount, result.RecordCount);
+ }
+
+ [Test]
+ public void GenericIEnumerableToCollectionViewModelConverter_ConvertsCorrectly()
+ {
+ // Arrange
+ var profile = new CommonMapperProfile();
+ var configuration = new MapperConfiguration(cfg => cfg.AddProfile(profile));
+ var mapper = new Mapper(configuration);
+ var items = new List { 1, 2, 3 };
+
+ // Act
+ var result = mapper.Map>(items);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.AreEqual(items.Count, result.Items.Count());
+ }
+
+ [Test]
+ public void CustomProfileConverter_ConvertsCorrectly()
+ {
+ // Arrange
+ var customProfile = new CustomMapperProfile();
+ var profile = new CommonMapperProfile();
+ var configuration = new MapperConfiguration(cfg =>
+ {
+ cfg.AddProfile(profile);
+ cfg.AddProfile(customProfile);
+ });
+
+ var mapper = new Mapper(configuration);
+ var customEntity = new CustomEntity { Id = 1, Name = "Custom Entity" };
+
+ // Act
+ var result = mapper.Map(customEntity);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.AreEqual(customEntity.Id, result.Id);
+ Assert.AreEqual(customEntity.Name, result.Name);
+ }
+
+ public class CustomMapperProfile : Profile
+ {
+ public CustomMapperProfile()
+ {
+ CreateMap();
+ }
+ }
+
+ public class CustomEntity
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+ }
+
+ public class CustomViewModel
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Test/BSN.Commons.AutoMapper.Tests/IServiceCollectionExtensionsTests.cs b/Test/BSN.Commons.AutoMapper.Tests/IServiceCollectionExtensionsTests.cs
new file mode 100644
index 0000000..9f30ca4
--- /dev/null
+++ b/Test/BSN.Commons.AutoMapper.Tests/IServiceCollectionExtensionsTests.cs
@@ -0,0 +1,24 @@
+using AutoMapper;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace BSN.Commons.AutoMapper.Tests
+{
+ public class IServiceCollectionExtensionsTests : AutoMapperTestBase
+ {
+ [Test]
+ public void AddAutoMapper_AddsMapperToServices()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+ var configure = new Action(config => { });
+
+ // Act
+ services.AddAutoMapper(configure);
+ var serviceProvider = services.BuildServiceProvider();
+
+ // Assert
+ var mapper = serviceProvider.GetService();
+ Assert.NotNull(mapper);
+ }
+ }
+}