3

我在玩 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);
        }
    }
}
4

1 回答 1

3

不,这是 ServiceStack 中的一个基本概念,即每个 Service 都需要自己独特的 Request DTO,请参阅此答案以获取更多示例

你可以这样做:

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

但我强烈建议不要在 DTO 中使用继承。属性声明就像服务合同的 DSL,它不应该被隐藏。

有关更多详细信息,请参阅有关 DTO 在 Services 中的目的的答案。

于 2013-04-10T19:40:16.060 回答