Extension Methods

Oct 7, 2011 at 7:05 AM

Hey Fabian, nice tool. I used it when we changed our applications to use WCF a month ago and it works like a charm.

one question: why do you implement an assembler class that needs know about the DTOs conversion logic instead of using extension methods on the Service's namespace that does the trick?

In the Common namespace you hold your DTO:

namespace Codeplex.Common.DataTransferObjects {

    [DataContract]
    public class ReservationDto : DtoBase {

        public ReservationDto() {
            time = DateTime.Now;
        }

        private DateTime time;
        [DataMember]
        public DateTime Time {
            get;
            set;
        }
    }
}

And then, in the Service namespace you have your DTOConverter class:

namespace Codeplex.Service.Wcf
{
    public static class DtoConverter
    {
        public static Reservation ConvertToEntity(this ReservationDto dto)
        {
            if (dto == null) { return null; }

            Reservation reservation = new Reservation
            {
                ReservationNr = dto.ReservationNr,
                Time= dto.Time
            };

            return reservation;
        }
        public static ReservationDto ConvertToDto(this Reservation reservation)
        {
            if (reservation == null) { return null; }

            return new ReservationDto
            {
                ReservationNr = reservation.ReservationNr,
                Time = reservation.Time
            };
        }
    }
}
The advantages are:
  • you do not need to instantiate an assembler/converter to make a Dto into an entity.
  • the entites know how to become a DTO and v.v

But maybe there is a good reason for your approach. (which I'd love to hear about)  :-)

Cheers,

Alex

Oct 7, 2011 at 7:13 AM

To make my point clearer... This is what your generated code looks like without extension methods...

namespace Codeplex.Assemblers
{    
    public partial class EventAssembler : AssemblerBase<Event, EventDTO>
    {
        #region Methods
        public override EventDTO ToDTO(Event entity)
        {
            var dto = new EventDTO();
            dto.EventId = entity.EventId;
            dto.Product = (new ProductAssembler()).ToDTO(entity.Product);
            this.OnDTO(dto);
            return dto;
        }
      #endregion Methods
    }
}
Oct 7, 2011 at 7:15 AM

This is what it could look like...

namespace Codeplex.Assemblers
{    
    public partial class EventAssembler : AssemblerBase<Event, EventDTO>
    {
        #region Methods
        public override EventDTO ToDTO(Event entity)
        {
            var dto = new EventDTO();
            dto.EventId = entity.EventId;
            dto.Product = entity.Product.ConvertToDto();
            this.OnDTO(dto);
            return dto;
        }
      #endregion Methods
    }
}
I know it's a detail, but don't like these new keywords in my code :D
Coordinator
Oct 7, 2011 at 10:13 PM

Hello aklee.

I think that your approach is very good and meets the objective, you gain simple invocation of conversion methods and a little more readable code. But you are giving more responsability to the DTO and the Entity, and also coding that responsability out of the class definition which adds complexity to the understanding of the solution.

EntitiesToDTOs presents an approach which I think is very accurate to comply with DTO pattern as specified by Martin Fowler. You can take a look at: http://martinfowler.com/eaaCatalog/dataTransferObject.html

It is also suitable for using Dependency Injection with Frameworks like Unity. If you use Dependency Injection you will not have to instatiate an Assembler every time you need to do a conversion.

Thing is that if I code assemblers to be static (which would lead you to not instantiate them) you could manage to get a bottle neck in a "big" application.

But I've never seen this pattern implemented using extension methods and I can only figure out the points I already mentioned, so maybe you can give me the good reasons of why using it and explain it to me a little more.

At the end, if both solutions are good, I can let the user decide which implementation to use: Extension Methods or Assemblers.

 

Thanks a lot for taking the time to make the comments and contribute with your opinion, and of course: for using EntitiesToDTOs!!!

 

Regards,

Fabian Fernandez

Oct 8, 2011 at 11:29 PM

Hey Fabian,

I agree form the architectural point of view... Your example has less complexity, even though there are more classes involved. In my case, we have a pretty large database. and we use over 40 entities with up to 90 fields to transfer via WCF... (so ugly!!!) So I care about every line of code I DON'T have to care about. :-D

However, I think your "bottleneck argument" doesn't count. Because the precompiler will tear the extensions apart and include the methods into the DTO / Entity classes as normal functions. So there is not one class that has to convert every single object, it's all the classes that know how to convert into their "anti-class"...

But from an architectural point of view, I think your example is neater. Mr. Fowler would say so too i'm sure! :-) 

I'm short on time so I'll just post one little example which I think could be interesting for you... (Since there is a little duplicated code smell in your AssemblerBase class).

public static List<Product> ConvertToEntities(this IEnumerable<ProductDto> dtos)
{
    return ConvertGenericList(dtos, ConvertToEntity);
}

public static List<ProductDto> ConvertToDtos(this IEnumerable<Product> reservationen)
{
    return ConvertGenericList(reservationen, ConvertToDto);
}
        
private static List<TTarget> ConvertGenericList<TSource, TTarget>(this IEnumerable<TSource> source, Func<TSource, TTarget> converter)
{
    if (source == null) { return null; }
    return source.Select(converter).ToList();
}

 Got it?! ;-)

Talk to you soon

Oct 8, 2011 at 11:37 PM

Ooops!! I almost forgot... I don't mean to be nit-picking (every psychologist would say now: "that's exactly what you are trying to do!! but anyway... )

By convetion, type parameters should always start with a 'T' so in your generic classes it should say:

public abstract class AssemblerBase<TEntityType, TDTOType>

my Resharper told me that ;-)

Coordinator
Oct 12, 2011 at 11:34 PM

Hi aklee.

Sorry for the late reply, I was very busy with work.

Thanks for your tip about the convention regarding generic types. Will modify that to comply. Also thanks for noting the code smell, that will be updated too.

Back again into the extension method discussion, let's forget about the bottle-neck, I think I didn't explained quite good, it wasn't regarding the extension methods in other source code files, it was about the possibility of making Assemblers static so you don't have to instantiate them, that would lead into a bottle-neck. Forget about it.

After reviewing your approach and following your arguments, I think that the extension methods solution is quite good. So I will schedule that for version 2.1 and credit you of course.

Thanks a lot.

If you have anything else to clarify about the extension methods solution, it will be welcome.

 

Regards,

Fabian Fernandez

Coordinator
Dec 31, 2011 at 2:40 AM

Hi aklee, finally I decided to use extension methods for the assemblers, you were right ;) it is the simplest solution and very clear. Soon I will upload v2.0 so you will be able to check the new assemblers.

Let me know what you think.

Thanks!

 

Regards,

Fabian Fernandez

Marked as answer by ffernandez on 12/30/2013 at 6:58 PM
Mar 13, 2012 at 11:04 AM

hi ffernandez and aklee,

First thank you for this great tool.

I don't understand why i can't see the extensions methods when i use DTO or Entity objects

 

Thanks for your help

Riadh

 

Coordinator
Mar 13, 2012 at 1:48 PM

Hello riadhgomri.

Thanks for using EntitiesToDTOs, I'm glad that you like the tool.

Please, verify that in the assembly where you need the extension methods (assemblers) you have a reference to the assembly where they are defined (if it is not the same assembly where you need to use them). Then in the source code where you need them you have to add a using statement in order to see the extension methods.

Let's say for example that your extension methods are defined in an assembly named "MyExtensionMethods.dll" under a namespace called "MySolution.MyExtensionMethods". Then you are using them in another assembly so this last one needs to have a reference to "MyExtensionMethods.dll". Also in this last assembly you have a source file which could be something like this:

using System;
using System.Text;
using MySolution.MyEntities;
using MySolution.MyDTOs;
using MySolution.MyExtensionMethods;

namespace MySolution.MyOtherAssembly
{
    public class Example
    {
        public void ExampleMethod()
        {
            // MyDTO is defined in "MySolution.MyDTOs"
            var dto = new MyDTO();
            
            // "ToEntity" extension method (assembler) is defined in "MySolution.MyExtensionMethods"
            // "MyEntity" is defined in "MySolution.MyEntities"
            MyEntity entity = dto.ToEntity();
        }
    }
}

Hope this helps!

Let me know if you have any doubt.

 

Regards,

Fabian Fernandez

Mar 13, 2012 at 8:42 PM
Edited Mar 13, 2012 at 8:49 PM

hi Fabian,

I added the reference and forgot the using, so it's working now :)

i make always the same mistake again and again when using extension methods, i add the reference but not the using, i always think that the compiler will use the extension in all the project but it did not, you have to add the using in each file/class you use them, hope next version of c# will 'fix' that.

Thanks again

Riadh