【问题标题】:Unit testing servicestack services with custom serialization / deserialization使用自定义序列化/反序列化对 servicestack 服务进行单元测试
【发布时间】:2012-03-29 02:43:42
【问题描述】:

我在测试提供了自己的反序列化机制的 Web 服务时遇到问题。

TaskService 正在使用的我的示例 Task 类:

public class Task
{
    public string TaskName { get; set; }
    public string AuxData { get; set; }

    public static void RegisterCustomSerialization(IAppHost appHost)
    {
        appHost.ContentTypeFilters.Register("application/xml", SerializeTaskToStream, DeserializeTaskFromStream);
    }

    public static void SerializeTaskToStream(IRequestContext requestContext, object response, Stream stream)
    {
        var tasks = response as List<Task>;
        if (tasks != null)
        {
            using (var sw = new StreamWriter(stream))
            {
                if (tasks.Count == 0)
                {
                    sw.WriteLine("<Tasks/>");
                    return;
                }

                sw.WriteLine("<Tasks>");
                foreach (Task task in tasks)
                {
                    if (task != null)
                    {
                        sw.WriteLine("  <Task type=\"new serializer\">");
                        sw.Write("    <TaskName>");
                        sw.Write(task.TaskName);
                        sw.WriteLine("</TaskName>");
                        sw.Write("    <AuxData>");
                        sw.Write(task.AuxData);
                        sw.WriteLine("</AuxData>");
                        sw.WriteLine("  </Task>");
                    }
                }
                sw.WriteLine("</Tasks>");
            }
        }
        else
        {
            var task = response as Task;
            using (var sw = new StreamWriter(stream))
            {
                if (task != null)
                {
                    sw.WriteLine("  <Task type=\"new serializer\">");
                    sw.Write("    <TaskName>");
                    sw.Write(task.TaskName);
                    sw.WriteLine("</TaskName>");
                    sw.Write("    <AuxData>");
                    sw.Write(task.AuxData);
                    sw.WriteLine("</AuxData>");
                    sw.WriteLine("  </Task>");
                }
            }
        }
    }

    public static object DeserializeTaskFromStream(Type type, Stream stream)
    {
        if (stream == null || stream.Length == 0)
            return null; // should throw exception?
        XDocument xdoc = XDocument.Load(stream);
        XElement auxData = xdoc.Root.Element("AuxData");

        return new Task() { AuxData = auxData.Value };
    }


    public override bool Equals(object obj)
    {
        Task task = obj as Task;
        if (task == null)
            return false;
        return TaskName.Equals(task.TaskName);
    }

    public override int GetHashCode()
    {
        return TaskName.GetHashCode();
    }
}

我的序列化/反序列化代码基于:http://www.servicestack.net/ServiceStack.Northwind/vcard-format.htmhttps://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/ServiceStack.Northwind/ServiceStack.Northwind.ServiceInterface/VCardFormat.cs

我的基础测试类如下:

public class SimpleRestTestBase : AppHostBase
{
    public SimpleRestTestBase() : base( "SimpleRestTestBase", typeof(TaskService).Assembly)
    {
        Instance = null;
        Init();
    }

    public override void Configure(Funq.Container container)
    {
        SetConfig(new EndpointHostConfig
        {
            DefaultContentType = ContentType.Xml
        }
        );

        Task.RegisterCustomSerialization(this);

        Routes
          .Add<Task>("/tasks/{TaskName}")
          .Add<List<Task>>("/tasks");

        container.Register(new List<Task>());
    }
}

以及失败的单元测试:

[TestFixture]
public class SimpleTest : SimpleRestTestBase
{
    [Test]
    public void TestMetodRequiringServer()
    {
        var client = (IRestClient)new XmlServiceClient("http://localhost:53967");
        var data = client.Get<List<Task>>("/api/tasks");
    }
}

我在使用 nUnit 测试运行器时遇到的异常是:

Testing.SimpleTest.TestMetodRequiringServer: System.Runtime.Serialization.SerializationException : Error in line 1 position 9. Expecting element 'ArrayOfTask' from namespace 'http://schemas.datacontract.org/2004/07/ServiceStackMVC'.. Encountered 'Element' with name 'Tasks', namespace ''.

如何将有关我的自定义序列化/反序列化代码的信息传递给XmlServiceClient

【问题讨论】:

    标签: c# servicestack


    【解决方案1】:

    您正在使用强耦合的自定义版本覆盖通用 XML 序列化格式 (application/xml),以仅处理 1 个 Web 服务输出 - 这很少是您想要的,因为它会阻止(即破坏)所有您的其他服务不会返回 XML。 如果要返回自定义 XML,只需通过返回 xml 字符串来限制需要它的服务。

    您无法更改 XmlServiceClient 的实现,因为它与 ServiceStack 使用的 XML 序列化/反序列化强耦合。您应该使用原始 HTTP 客户端来发送所需的确切 XML 有效负载。这是一个使用 .NET 的 Web 请求发送原始 XML 的示例: https://stackoverflow.com/a/8046734/85785

    由于您要返回并发送自定义 XML,您可能还希望为您的 Web 服务覆盖自定义请求绑定器,以便您有机会以您想要的方式反序列化请求。

    有关如何执行此操作的一些示例,请参见下面的 wiki 页面:

    https://github.com/ServiceStack/ServiceStack/wiki/Serialization-deserialization

    注意:返回自定义 XML 并不理想,因为它绕过了 ServiceStack 强类型、智能和固执己见的许多优点。

    【讨论】:

    • 感谢您指出 appHost.ContentTypeFilters.Register 会影响所有使用/返回 Content-Type 设置为“application/xml”的 HTTP 消息的服务(这就是我现在的理解)。 CustomRequestBinder 只允许我自定义序列化,对吗?控制数据的序列化方式怎么样?
    • Request Binder 允许自定义反序列化参见stackoverflow.com/questions/6245616/…,了解不同返回类型的示例。即您可以只返回一个字符串,否则您可以添加自己的 ResponseFilter 以直接写入响应,请参阅:github.com/ServiceStack/ServiceStack/wiki/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-24
    • 1970-01-01
    相关资源
    最近更新 更多