ServiceStack是否支持端到端类型请求中的泛型

时间:2013-04-10 19:29:43

标签: servicestack

我正在玩ServiceStack并且想知道它是否支持这种情况。我在我的请求类型中使用泛型,以便从公共接口继承的许多DTO将支持相同的基本方法[如... GetById(int Id)]。

使用特定于某种DTO的请求类型,但打破了泛型的好处......

var fetchedPerson = client.Get<PersonDto>(new PersonDtoGetById() { Id = person.Id });
Assert.That(person.Id, Is.EqualTo(fetchedPerson.Id)); //PASS

将路线映射到通用也有效:

Routes.Add<DtoGetById<PersonDto>>("/persons/{Id}", ApplyTo.Get);
...
var fetchedPerson2 = client.Get<PersonDto>(string.Format("/persons/{0}", person.Id));
Assert.That(person.Id, Is.EqualTo(fetchedPerson2.Id)); //PASS

但是使用端到端通用请求类型失败:

var fetchedPerson3 = client.Get<PersonDto>(new DtoGetById<PersonDto>() { Id = person.Id });
Assert.That(person.Id, Is.EqualTo(fetchedPerson3.Id)); //FAIL

我想知道我是否只是遗漏了一些东西,或者我是否想要将ooone层抽象得太远......:)

下面是一个完整的,失败的程序,使用NUnit,默认的ServiceStack东西:

namespace ssgenerics
{
    using NUnit.Framework;
    using ServiceStack.ServiceClient.Web;
    using ServiceStack.ServiceHost;
    using ServiceStack.ServiceInterface;
    using ServiceStack.WebHost.Endpoints;

    [TestFixture]
    class Program
    {
        public static PersonDto GetNewTestPersonDto()
        {
            return new PersonDto()
            {
                Id = 123,
                Name = "Joe Blow",
                Occupation = "Software Developer"
            };
        }

        static void Main(string[] args)
        {}

        [Test]
        public void TestPutGet()
        {
            var listeningOn = "http://*:1337/";
            var appHost = new AppHost();
            appHost.Init();
            appHost.Start(listeningOn);
            try
            {

                var BaseUri = "http://localhost:1337/";
                var client = new JsvServiceClient(BaseUri);

                var person = GetNewTestPersonDto();
                client.Put(person);

                var fetchedPerson = client.Get<PersonDto>(new PersonDtoGetById() { Id = person.Id });
                Assert.That(person.Id, Is.EqualTo(fetchedPerson.Id));

                var fetchedPerson2 = client.Get<PersonDto>(string.Format("/persons/{0}", person.Id));
                Assert.That(person.Id, Is.EqualTo(fetchedPerson2.Id));
                Assert.That(person.Name, Is.EqualTo(fetchedPerson2.Name));
                Assert.That(person.Occupation, Is.EqualTo(fetchedPerson2.Occupation));

                var fetchedPerson3 = client.Get<PersonDto>(new DtoGetById<PersonDto>() { Id = person.Id });
                Assert.That(person.Id, Is.EqualTo(fetchedPerson3.Id));
                Assert.That(person.Name, Is.EqualTo(fetchedPerson3.Name));
                Assert.That(person.Occupation, Is.EqualTo(fetchedPerson3.Occupation));
            }
            finally
            {
                appHost.Stop();
            }
        }
    }

    public interface IDto : IReturnVoid
    {
        int Id { get; set; }
    }

    public class PersonDto : IDto
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Occupation { get; set; }
    }

    public class DtoGetById<T> : IReturn<T> where T : IDto { public int Id { get; set; } }
    public class PersonDtoGetById : IReturn<PersonDto> { public int Id { get; set; } }

    public abstract class DtoService<T> : Service where T : IDto
    {
        public abstract T Get(DtoGetById<T> Id);
        public abstract void Put(T putter);
    }

    public class PersonService : DtoService<PersonDto>
    {
        public override PersonDto Get(DtoGetById<PersonDto> Id)
        {
            //--would retrieve from data persistence layer
            return Program.GetNewTestPersonDto();
        }

        public PersonDto Get(PersonDtoGetById Id)
        {
            return Program.GetNewTestPersonDto();
        }

        public override void Put(PersonDto putter)
        {
            //--would persist to data persistence layer
        }
    }

    public class AppHost : AppHostHttpListenerBase
    {
        public AppHost()
            : base("Test HttpListener",
                typeof(PersonService).Assembly
                ) { }

        public override void Configure(Funq.Container container)
        {
            Routes.Add<DtoGetById<PersonDto>>("/persons/{Id}", ApplyTo.Get);
        }
    }
}

1 个答案:

答案 0 :(得分:3)

不,ServiceStack中的一个基本概念是每个服务都需要自己的唯一请求DTO ,请参阅this answer for more examples on this

你可以这样做:

[Route("/persons/{Id}", "GET")]
public class Persons : DtoGetById<Person> { ... }   

但我强烈advise against using inheritance in DTOs。财产声明就像服务合同的DSL,而不是应隐藏的东西。

有关详细信息,请参阅此答案on the purpose of DTO's in Services