4

I need to make a commons methods to my services, and use a Repository or other depending of the object type I am passing as argument.

For example, I have these interfaces:

public interface IServiceText
{
   Task<string> UpdateTextPosition(TextDto object);
   Task<string> UpdateTextSize(TextDto object);
   Task<string> UpdateOtherThingOnText(TextDto object);

}

public interface IServiceImage
{
   Task<string> UpdateImagePosition(ImageDto object);
   Task<string> UpdateImageSize(ImageDto object);
   Task<string> UpdateOtherThingOnImage(ImageDto object);

}

In the order hand, I have the classes that implements the Interfaces (just important code added) and with the constructors:

//Class ServiceImage
private readonly IRepository<Image> _repo;

public ServiceImage(IRepository<Image> repo) //Dependecy Injection of the IRepository Generic
{
    _repo = repo;
}

//Class ServiceText
private readonly IRepository<Text> _repo;

public ServiceText(IRepository<Text> repo) //Dependecy Injection of the IRepository Generic
{
    _repo = repo;
}

The UpdateTextPosition and UpdateImagePosition do exactly the same thing, but in differents collections (or using differents IRepository instances, I'm using MongoDB):

public async Task<string> UpdateTextPosition(TextDto object)
{
     var text = await _repo.FindAsync(object.Id);
     text.PosLeft = object.PosLef;
     text.PosRight = object.PosRight;
     await _repo.Update(text); 
     return text.Id; 

}

public async Task<string> UpdateImagePosition(ImageDto object)
{
     var image = await _repo.FindAsync(object.Id);
     image.PosLeft = object.PosLef;
     image.PosRight = object.PosRight;
     await _repo.Update(image);  
     return image.Id

}

EDIT: (added ImageDto and TextDto)

public class ImageDto
{
     public ObjectId Id {get; set;}
     public int PosLeft {get; set;}
     public int PosTop {get; set;}
     public ICollection<string> PropertyImage1 {get; set;}
     public string PropertyImage2 {get; set;}
}


public class TextDto
{
     public ObjectId Id {get; set;}
     public int PosLeft {get; set;}
     public int PosTop {get; set;}
     public double PropertyText1 {get; set;}
     public string PropertyText2 {get; set;}
}

public class Image : Entity
    {
         public ObjectId Id {get; set;}
         public int PosLeft {get; set;}
         public int PosTop {get; set;}
         public ICollection<string> PropertyImage1 {get; set;}
         public string PropertyImage2 {get; set;}
         public string OtherPropertyImage {get; set;}
    }


public class Text : Entity
{
     public ObjectId Id {get; set;}
     public int PosLeft {get; set;}
     public int PosTop {get; set;}
     public double PropertyText1 {get; set;}
     public string PropertyText2 {get; set;}
     public string OtherPropertyText {get; set;}
}

And the IEntity:

/// <summary>
/// Generic Entity interface.
/// </summary>
/// <typeparam name="TKey">The type used for the entity's Id.</typeparam>
public interface IEntity<TKey>
{
    /// <summary>
    /// Gets or sets the Id of the Entity.
    /// </summary>
    /// <value>Id of the Entity.</value>
    [BsonId]
    TKey Id { get; set; }
}

/// <summary>
/// "Default" Entity interface.
/// </summary>
/// <remarks>Entities are assumed to use strings for Id's.</remarks>
public interface IEntity : IEntity<string>
{
}

And Entity class:

/// <summary>
    /// Abstract Entity for all the BusinessEntities.
    /// </summary>
    //[DataContract]
    [Serializable]
    [BsonIgnoreExtraElements(Inherited = true)]
    public abstract class Entity : IEntity<string>
    {
        /// <summary>
        /// Gets or sets the id for this object (the primary record for an entity).
        /// </summary>
        /// <value>The id for this object (the primary record for an entity).</value>
        [DataMember]
        [BsonRepresentation(BsonType.ObjectId)]
        public virtual string Id { get; set; }
    }

I need to move the "common methods" in a new CommonService with an Interface (ICommonService), and take the object type and identify what IMongoRepository use... I think that Generic is my way... but I have read about it, but I don't understand very well the examples and I would like to the best way to implement this in my real solution.

Thank you soooo much!!

6
  • Do the other methods also look alike (e.g. UpdateOtherThingOnText and UpdateOtherThingOnImage)? or just the methods you provided? Can you show the definition of ImageDto and TextDto? Commented Dec 15, 2015 at 21:56
  • @YacoubMassad Hi! I have added ImageDto and TextDto class :) Nop, the other methods are totally differents. Commented Dec 15, 2015 at 22:06
  • So you want to create a service that has a single method called something like UpdatePosition that works on both ImageDto and TextDto and maybe more other DTOs, right? Commented Dec 15, 2015 at 22:15
  • Sorry @YacoubMassad I didn't understand your last question... The method UpdatePosition and UpdateSize do the same. Update UpdateOtherThingOnText and UpdateOtherThingOnImage not. Thanks again!! Commented Dec 15, 2015 at 22:18
  • Can you also show the definition of Text and Image? Commented Dec 15, 2015 at 22:21

1 Answer 1

4

If I understood your question correctly, then you should do something that looks like this:

First create a common interface for your DTOs:

public interface IDtoCommon
{
    ObjectId Id { get; set; }
    int PosLeft { get; set; }
    int PosTop { get; set; }
}

And a common interface for your entities:

public interface IEntityCommon
{
    ObjectId Id { get; set; }
    int PosLeft { get; set; }
    int PosTop { get; set; }
}

So here is how your DTOs and entities would look like:

public class ImageDto : IDtoCommon
{
     public ObjectId Id {get; set;}
     public int PosLeft {get; set;}
     public int PosTop {get; set;}
     public ICollection<string> PropertyImage1 {get; set;}
     public string PropertyImage2 {get; set;}
}


public class TextDto : IDtoCommon
{
     public ObjectId Id {get; set;}
     public int PosLeft {get; set;}
     public int PosTop {get; set;}
     public double PropertyText1 {get; set;}
     public string PropertyText2 {get; set;}
}

public class Image : Entity, IEntityCommon
{
    public ObjectId Id { get; set; }
    public int PosLeft { get; set; }
    public int PosTop { get; set; }
    public ICollection<string> PropertyImage1 { get; set; }
    public string PropertyImage2 { get; set; }
    public string OtherPropertyImage { get; set; }
}

public class Text : Entity, IEntityCommon
{
    public ObjectId Id { get; set; }
    public int PosLeft { get; set; }
    public int PosTop { get; set; }
    public double PropertyText1 { get; set; }
    public string PropertyText2 { get; set; }
    public string OtherPropertyText { get; set; }
}

And here is how your common service would look like:

public interface ICommonService<TDto> where TDto : IDtoCommon
{
    Task<string> UpdatePosition(TDto @object);
}

public class CommonService<TDto, TEntity> : ICommonService<TDto>
    where TDto : IDtoCommon
    where TEntity : IEntityCommon
{
    private readonly IRepository<TEntity> m_Repository;

    public CommonService(IRepository<TEntity> repository)
    {
        m_Repository = repository;
    }

    public async Task<string> UpdatePosition(TDto @object)
    {
        var entity = await m_Repository.FindAsync(@object.Id);
        entity.PosLeft = @object.PosLeft;
        entity.PosTop = @object.PosTop;
        await m_Repository.Update(entity);
        return entity.Id.Value; 
    }
}

And here is an example of how it can be used:

CommonService<TextDto, Text> service = new CommonService<TextDto, Text>(new Repository<Text>());

service.UpdatePosition(text_dto);

You should think about whether you have enough repetition in your code to justify doing all of this.

Sign up to request clarification or add additional context in comments.

5 Comments

Hi! Your answer is amazing, thank you so much for your time. I think this a good example for other developers... I'm worry about performance... What do you think? You say "thinking about this solution"... Can you please tell a reference to decide what solution is better? Repeat or Generic Classes?
I don't think there is a performance issue. My note was about how much repetition does this solution save you? You should decide if you used less code by using this solution. Does it save more lines of code than the lines of code it adds (and the complexity it adds)?
we are talking about 6 methods and 5 objects... What do you think? :)
Sorry, 8 methods... ;)
In this case, I would say it is probably worth it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.