Coder Social home page Coder Social logo

hasanaltan-cpu / social_media_project Goto Github PK

View Code? Open in Web Editor NEW
5.0 1.0 0.0 3.25 MB

In this repository,my main goal is to demonstrate my asp.netcore skills on Domain Driven Design Architecture.For this , i use this architecture for build up my application as image in the ReadMe.U can reach in this repository also ExternalLogin for GoogleAuthentication.I provide two factor authentication to application members.Moreover,members who is signed in the application can chat in messenger.In this part of the Social_Media_project i used SignalR for real time communication.In addition to that members can schedule their calendar programme as birthday,sleeping time,lunch etc.By using this application members can post the others.The others can like and mention(comment) to post.All members be able to follow each other.As i mentioned before,users can find them by using Search tab.(Email,Name,UserName).I use UnitOfWork for all transactions.I use Async Programming & Code First.I try to write all codes in the light of Solid Principle & OOP rules.

C# 28.54% HTML 9.26% CSS 26.89% JavaScript 35.32%
asp-net-core asp-net-core-mvc identity-management unitofwork signalr-core googleauthenticaion fluentvalidation domaindrivendesign ddd-architecture automapper

social_media_project's Introduction

DDD

Domain Driven Design architecture schema.

In this project i use these packages & tools :
  • Microsoft.AspNetCore.SignalR(v1.1.0)
  • Microsoft.AspNetCore.Authentication.Google(v3.1.6)
  • Microsoft.AspNetCore.Mvc.NewtonsoftJson(v3.1.7)
  • Microsoft.VisualStudio.Web.CodeGeneration.Design(v3.1.5)
  • Automapper(v10.1.1),
  • FluentValidation.AspNetCore(v9.5.1),
  • Microsoft.AspNetCore.Identity(v9.5.3)
  • Microsoft.extensions.Hosting(v.3.1.6)
  • SixLabors.ImageSharp(v1.0.0)
  • Microsoft.EntityFrameworkCore(v3.1.6)
  • Microsoft.Extensions.Identity.Stores(v3.1.6)
  • Microsoft.AspNetCore.Identity.EntityFrameWorkCore(v3.1.6)
  • Microsoft.EntityFrameworkCore.Design(v3.1.6)
  • Microsoft.EntityFrameWorkCore.SqlServer(v3.1.6)
  • Microsoft.EntityFrameWorkCore.SqlServer.Design(v1.1.6)
  • Microsoft.EntityFrameWorkCore.Tools(v3.1.6)
  • AutoMapper.Extensions.Microsoft.DependencyInjection(v8.0.1)
  • AdminLTE v.3.0.5 for Theme

1-1-First of all,open a Blank Solution.

2- Social_Media_Project.DomainLayer will open as a .Net Core Library Project.

2.1.Create an Enums folder.

2.2.Create an Entities folder.

2.2.1. Open an Interface folder.

2.2.2.Create IBase type and IBaseEntity interface classes.

  public interface IBaseEntity
{
    DateTime CreateDate { get; }

    DateTime? ModifiedDate { get; set; }
    DateTime? DeletedDate { get; set; }

    Status Status { get; set; }
}

2.2.3.Create any entities what you need.

Note:At the user process step,i will use .Net Core Identity class that's why AppUserRole and AppUser classes will inherit from Identity class.

public class AppUser :IdentityUser<int>, IBaseEntity
{
    public AppUser()
    {
        Posts = new List<Post>();
        Shares = new List<Share>();
        Likes = new List<Like>();
        Mentions = new List<Mention>();
        Followers = new List<Follow>();
        Followings = new List<Follow>();
        Messages = new HashSet<Message>();
    }

    public virtual ICollection<Message> Messages { get; set; }
    public string Name { get; set; }

    public string ImagePath { get; set; } = "/images/users/default.jpg";

    public DateTime CreateDate { get { return DateTime.Now; } private set { } }

    public DateTime? ModifiedDate { get; set; }

    public DateTime? DeletedDate { get; set; }

    public Status Status { get; set; }

    public List<Post> Posts { get; set; }

    public List<Share> Shares { get; set; }

    public List<Like> Likes { get; set; }
    public List<Mention> Mentions { get; set; }

    [InverseProperty("Follower")]
    public List<Follow> Followers { get; set; }

    [InverseProperty("Following")]

    public List<Follow> Followings { get; set; }

}

What is the InverseProperty?

-Inverse Property attribute is used when you need to indicate that navigation property Follower is related to the same foreign key as another navigation property Following.

2.3.Create a Repositories folder.In this project,i create methods which async programming for the CRUD operations. For DIP create an Interfaces for each entity. Don't create IAppRole because of ORM . This class just uses for entity.

  public class AppUserRepository:BaseRepository<AppUser>,IAppUserRepository
{
    public AppUserRepository(ApplicationDbContext context) : base(context) { }
}	

2.4.Create an UnitofWork folder => IUnitOfWork.cs interface.In this part,i add repositories which i need to use to interface of UnitofWork.

What is the UnitOfWork?

-As u know,every transaction has expense for the database in terms of bringing data.UnitOfWork provide us to all transaction just goes from one bridge to database,furthermore,
after all transaction we use just one SaveChanges().

public  interface IUnitOfWork :IAsyncDisposable => IAsyncDisposable means , an object whic was created by class it will be delete from heap part of RAM after UnitofWork will be done.
{
   IPostRepository Post { get; }

   IMentionRepository Mention { get; }

   IAppUserRepository AppUser { get; }

    IFollowRepository Follow { get; }
    ILikeRepository Like { get; }
    IShareRepository Share { get; }

    Task Commit();

    Task ExecuteSqlRaw(string sql, params object[] parameters);

}

3-Social_Media_Project.InfrastructureLayer ClassLibrary(.Core) Project is opened.

3.1.Create a Mapping folder.Create Abstract & Concrete Folders. Mapping process is completed here.

public abstract class BaseMap: IEntityTypeConfiguration where T: class,IBaseEntity => We mapping here what we need to relationship on the SQL Database. {

    public virtual void Configure(EntityTypeBuilder<T> builder)
    {
        builder.Property(x => x.Status).IsRequired(true);
        builder.Property(x => x.CreateDate).IsRequired(true);
        builder.Property(x => x.ModifiedDate).IsRequired(false);
        builder.Property(x => x.DeletedDate).IsRequired(false);
    }
}

3.2.Create a Context folder.Create an AppLicationDbContex.cs.

public class ApplicationDbContext:IdentityDbContext<AppUser,AppRole,int> { public ApplicationDbContext(DbContextOptions options) : base(options) { }

    public DbSet<Post> Posts { get; set; }
    public DbSet<Mention> Mentions { get; set; }
    public DbSet<AppUser> AppUsers { get; set; }
    public DbSet<AppRole> AppRoles { get; set; }
    public DbSet<Like> Likes { get; set; }
    public DbSet<Share> Shares { get; set; }
    public DbSet<Follow> Follows { get; set; }
    public DbSet<Message> Messages { get; set; }


    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.ApplyConfiguration(new MessageMap());
        builder.ApplyConfiguration(new PostMap());
        builder.ApplyConfiguration(new MentionMap());
        builder.ApplyConfiguration(new AppUserMap());
        builder.ApplyConfiguration(new ShareMap());
        builder.ApplyConfiguration(new LikeMap());
        builder.ApplyConfiguration(new FollowMap());
        base.OnModelCreating(builder);
    }

3.3.Create a Repositories folder.Repositories will be contrete on this part from Interface.

public  interface IAppUserRepository:IRepository<AppUser> => With this way, we handle a losecoupled classes.
{
}

3.4.create a UnitofWork folder.

public class UnitOfWork : IUnitOfWork { private readonly ApplicationDbContext _db; public UnitOfWork(ApplicationDbContext db) { this._db = db ?? throw new ArgumentNullException("Database can not be null");

    }
    private IPostRepository _postRepository;
    public IPostRepository Post { get { return _postRepository ?? (_postRepository = new PostRepository(_db)); } }
    private IMentionRepository _mentionRepository;
    public IMentionRepository Mention {  get { return _mentionRepository ?? (_mentionRepository = new MentionRepository(_db)); } }
    private IAppUserRepository _appUserRepository;
    public IAppUserRepository AppUser { get { return _appUserRepository ?? (_appUserRepository = new AppUserRepository(_db)); } }
    private IFollowRepository _followRepository;
    public IFollowRepository Follow { get { return _followRepository ?? (_followRepository = new FollowRepository(_db)); } }
    private ILikeRepository _likeRepository;
    public ILikeRepository Like { get { return _likeRepository ?? (_likeRepository = new LikeRepository(_db)); } }
    private IShareRepository _shareRepository;
    public IShareRepository Share { get { return _shareRepository ?? (_shareRepository = new ShareRepository(_db)); } }
    
    public async  Task Commit()
    {
        await _db.SaveChangesAsync();
    }

    private bool isDisposed = false;
    public async  ValueTask DisposeAsync()
    {
        if (!isDisposed)
        {
            isDisposed = true;
            await DisposeAsync(true);
            GC.SuppressFinalize(this);
        };
    }

    protected async ValueTask DisposeAsync(bool disposing)
    {
        if (disposing)
        {
            await _db.DisposeAsync();
        }
    }
    public async  Task ExecuteSqlRaw(string sql, params object[] parameters)
    {
        await _db.Database.ExecuteSqlRawAsync(sql,parameters);
    }
}

3.5.EntityFrameworkCore.SqlServer&EntityFrameWorkCore.Tools packages is downloaded.

4-Social_Media_Project.ApplicationLayer ClassLibrary(.Core) Project is opened.

4.1.Create Models folder.In this folder includes Data Transfer Objects(DTOs) and View Models (Vms).

4.2.Implement the AutoMapper.

You can download from NuGet Package Manager or u can write to console window:

PM> Install-Package AutoMapper

*Why we need Automapper?

-We need to transfer some datas from database to model for to use.In this part,we use Data Transfer Object (DTO).In addition to that,thanks to AutoMapper first usage is primitive i mean it is oldschool but the second one is beneficials of AutoMapper.We don't need to write all properties for pointing out EntityModel & EntityDto relationship.

The First One;

var config = new MapperConfiguration(cfg => { cfg.CreateMap<EntityModel, EntityDTO>(); }); IMapper iMapper = config.CreateMapper(); var source = new AuthorModel(); entity.Id = 1;
entity.FirstName = "Hasan"; entity.LastName = "ALTAN"; entity.Address = "Turkey"; var destination = iMapper.Map<EntityModel, EntityDTO>(source);

AutoMapper; public Mapping() { CreateMap<AppUser, RegisterDto>().ReverseMap(); CreateMap<AppUser, LoginDto>().ReverseMap(); CreateMap<AppUser, ExternalLoginDto>().ReverseMap(); CreateMap<AppUser, EditProfileDto>().ReverseMap(); CreateMap<AppUser, ProfileSummaryDto>().ReverseMap(); CreateMap<Follow, FollowDto>().ReverseMap(); CreateMap<Like, LikeDto>().ReverseMap(); CreateMap<Post, SendPostDto>().ReverseMap();

        CreateMap<Mention, MentionDto>()
            .ForMember(d => d.Name, opt => opt.MapFrom(s => s.AppUser.Name))
            .ForMember(d => d.UserName, opt => opt.MapFrom(s => s.AppUser.UserName))
            .ForMember(d => d.UserImage, opt => opt.MapFrom(s => s.AppUser.ImagePath))
            .ReverseMap();

        CreateMap<Mention, AddMentionDto>().ReverseMap();
    }

4.2.1.Create a folder which name is Mapper.Mapping.cs class is created.Mapping.cs inherited from Profile.cs that's why we should download AutoMapper package.

4.2.2.AutoMapper & AutoMapper.DependencyInjection packages download to dependencies.

4.3.Create a folder which name is InversionOfControl then create DependencyInjection class.In this class,all coupled classes will register and resolve.In this project i use Built-in Container but we can choose another container as a 3rd part Autofact.

4.4.Create a Services folder.

Note:SixLabors.ImageSharp was downloaded for "Image Process".

4.4.1.Create Services=>Interfaces folder.For using PresentationLayer we create service interface.

public interface IAppUserService { Task DeleteUser(params object[] parameters);

    Task<IdentityResult> Register(RegisterDto model);

    Task<SignInResult> Login(LoginDto model);

    Task LogOut();

    Task<int> UserIdFromName(string UserName);

    AuthenticationProperties ExternalLogin(string provider, string redirectUrl);

    Task<ExternalLoginInfo> GetExternalLoginInfo();

    Task<SignInResult> ExternalLoginSignIn(string provider, string key);

    Task<IdentityResult> ExternalRegister(ExternalLoginInfo info, ExternalLoginDto model);

    Task<EditProfileDto> GetById(int id);

    Task EditUser(EditProfileDto id);

    Task<ProfileSummaryDto> GetByName(string userName);

    Task<List<SearchUserDto>> SearchUser(string keyword,int pageIndex);

    Task<List<FollowListVm>> UsersFollowings(int id, int pageIndex);

    Task<List<FollowListVm>> UsersFollowers(int id, int pageIndex);

}

4.4.2.Create Services=>Concrete folder.For the services , we use service interface methods body.

  *This is just an example for task body part.
  
    public async Task DeleteUser(params object[] parameters)
    {
        await _unitOfWork.ExecuteSqlRaw("spDeleteUsers {0}", parameters);
    }

4.5.IoC=>InversionOfControl folder is opened.Then Register and Resolver on the DependencyInjection class.

public static class DependencyInjection { public static IServiceCollection RegisterServices(this IServiceCollection services) { services.AddAutoMapper(typeof(Mapping));

        services.AddScoped<IUnitOfWork, UnitOfWork>();
        services.AddScoped<IAppUserService, AppUserService>();
        services.AddScoped<IFollowService, FollowService>();
        services.AddScoped<ILikeService, LikeService>();
        services.AddScoped<IPostService, PostService>();
        services.AddScoped<IMentionService, MentionService>();

       

        services.AddIdentity<AppUser, AppRole>(x =>
         {
             x.SignIn.RequireConfirmedPhoneNumber = false;
             x.SignIn.RequireConfirmedAccount = false;
             x.SignIn.RequireConfirmedEmail = false;
             x.User.RequireUniqueEmail = true;
             x.Password.RequiredLength = 1;
             x.Password.RequiredUniqueChars = 0;
             x.Password.RequireUppercase = false;
             x.Password.RequireNonAlphanumeric = false;
             x.Password.RequireLowercase = false;
         }).AddEntityFrameworkStores<ApplicationDbContext>();
        return services;
    }

}

4.6.Create a Services=>Extensions=> ClaimPrincipleExtension.cs class.Create some rules for getting users informations.

public static class ClaimsPrincipalExtensions { public static string GetUserEmail(this ClaimsPrincipal principal) { return principal.FindFirstValue(ClaimTypes.Email); }

    public static int GetUserId (this ClaimsPrincipal principal)
    {
        return (Convert.ToInt32(principal.FindFirstValue(ClaimTypes.NameIdentifier)));
    }

    public static string GetUserName (this ClaimsPrincipal principal)
    {
        return principal.FindFirstValue(ClaimTypes.Name);

    }

    public static bool IsCurrentUser(this ClaimsPrincipal principal,string id)
    {
        var currentUserId = GetUserId(principal).ToString();
        return string.Equals(currentUserId, id, StringComparison.OrdinalIgnoreCase);
    }
}

4.7.Services=>Validations folder is opened.

	**FluentValidation.AspNetCore package is installed.

  public class LoginValidation: AbstractValidator<LoginDto>  ---->FluentValidation provides us AbstractValidator parent class.
{
    public LoginValidation()
    {
        RuleFor(x => x.UserName).NotEmpty().WithMessage("Enter a UserName");
        RuleFor(x => x.Password).NotEmpty().WithMessage("Please Enter a Password");
    }
  
}

public  class ExternalLoginValidation:AbstractValidator<ExternalLoginDto>
{
    public ExternalLoginValidation()
    {
        RuleFor(x => x.Email).NotEmpty().WithMessage("Enter a Email adress").EmailAddress().WithMessage("Please Enter a valid E-mail adress.");

        RuleFor(x => x.Name).NotEmpty().WithMessage("Enter a Name").MinimumLength(3).MaximumLength(50).WithMessage("Minimum 3, Maximum 50 character please.");

        RuleFor(x => x.UserName).NotEmpty().WithMessage("Enter a UserName").MinimumLength(3).MaximumLength(50).WithMessage("Minimum 3 , Maximum 50 character please.");

    }
}

4.8.Social_Media_Project Asp.Net Core (Web Project) is opened.

4.8.1.Open a controller for every Model&View entity.

For instance;
 public class MessageController : Controller
{
   
    public readonly ApplicationDbContext _context;
    public readonly UserManager<AppUser> _userManager;
    public MessageController(UserManager<AppUser> userManager,
                             ApplicationDbContext context)
    {
        _context = context;
        _userManager = userManager;
    }
    [Authorize]

    public async Task<IActionResult> Messenger()
    {
        var currentUser = await _userManager.GetUserAsync(User);
        if (User.Identity.IsAuthenticated)
        {
            ViewBag.CurrentUserName = currentUser.UserName;
        }
        
        var messages = await _context.Messages.ToListAsync();
        return View(messages);
    }


    public async Task<IActionResult> Create(Message message)
    {
        if (ModelState.IsValid)
        {
            message.UserName = User.Identity.Name;
            var sender = await _userManager.GetUserAsync(User);
            message.UserId = sender.Id;
            await _context.Messages.AddAsync(message);
            await _context.SaveChangesAsync();
            return Ok();
        }
        return BadRequest("Opps something has been wrong..");
    }
}

social_media_project's People

Contributors

hasanaltan-cpu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.