本文介绍了ServiceStack 是否支持端到端类型化请求中的泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I was playin' around with ServiceStack and was wondering if it supported this scenario. I'm using generics in my request types so that many DTOs that inherit from a common interface will support the same basic methods [ like... GetById(int Id) ].

使用特定于单一类型 DTO 的请求类型有效,但破坏了泛型的优点...

Using a request type specific to a single kind of DTO works, but breaks the generics nice-ness...

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

将路由映射到泛型也有效:

Mapping a route to the generic also works:

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

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

But using the end-to-end generic request type fails:

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

我想知道我是否只是遗漏了什么,或者我是否试图将ooone层抽象得太远...... :)

I wonder if I'm just missing something, or if i'm trying to abstract just ooone layer too far... :)

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

Below is a complete, failing program using NUnit, default ServiceStack stuff:

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);
        }
    }
}

推荐答案

不,ServiceStack 中的一个基本概念是每个 Service 都需要自己的唯一请求 DTO,请参阅 有关此问题的更多示例的答案.

No, It's a fundamental concept in ServiceStack that each Service requires its own unique Request DTO, see this answer for more examples on this.

你可以这样做:

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

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

But I strongly advise against using inheritance in DTOs. Property declaration is like a DSL for a service contract and its not something that should be hidden.

有关更多详细信息,请参阅此答案关于服务中 DTO 的目的.

For more details see this answer on the purpose of DTO's in Services.

这篇关于ServiceStack 是否支持端到端类型化请求中的泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-16 19:09