servicestack在uri中传递斜杠 [英] servicestack pass forward slash in uri

查看:142
本文介绍了servicestack在uri中传递斜杠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用servicestack来构建一个web api,通过网络提供一些旧的数据。不幸的是,数据模式对于ServiceStack.Ormlite的标准使用并不是很好。例如,没有主键,在一个表上,(非唯一)键实际上可以包含任何字符。在我的示例数据库中,密钥中有'/'字符。



因此,当使用此路由从web api请求资源时/ api / objects / {objectCode} 如果所需的objectCode为1/1,路由应为/ api / objects / 1/1,但这会导致页面未找到异常。当我在以下路由上请求资源时,怎么办?/ api / objects / {objectCode} / subObjects


  1. 任何人都知道我应该如何解决这个问题?我应该围绕这个问题进行设计,还是有什么可以做的呢?


  2. 同样,我希望能够传递一个数组的这些objectCodes,但是我不能保证objectCode值中不会有一个,所以分隔符将出现在资源代码中,因此ServiceStack的分隔符解析,否?


我已经搜索了线索,但只发现人们询问查询字符串中的编码,而不是URI本身

解决方案

不幸的是,在URL中使用正斜杠,逗号和其他不寻常的字符会产生不良结果,显然不容易在您的路线工作。但是可以通过对Id值进行编码来解决这个问题。



我们可以使用ServiceStack的非常灵活的过滤器来使编码和解码的值完全透明到现有的ServiceStack服务。



透明编码/解码复杂Id值



此方法将使用请求和响应过滤器属性:




  • 请求过滤器将负责解码任何编码的Id值。

  • 响应过滤器将负责编码普通Id值。



所以Id值将始终在传输过程中编码,并在服务器端服务实现中完全解码。 b
$ b



例如: http:// localhost:8081 / Object / SGVsbG8vU29tZXRoaW5nL0Nvb2w =,VGhpcy9Jcy9BL VRlc3Q6SWQ =

  [UsesEncodedAttribute] 
[Route / Object / {Ids},GET)]
public class GetObjectWithComplexIdRequest:IReturn< ObjectWithComplexIdResponse>
{
[EncodedId]
public string [] Ids {get;组;
}

[UsesEncodedAttribute]
public class ObjectWithComplexIdResponse
{
[EncodedId]
public string [] Ids {get;组; }
}


I'm using servicestack to build a web api serving some old data over the web. Unfortunately the data schema does not lend itself particularly well to the standard use of ServiceStack.Ormlite. For example there are no primary keys and on one table the (non-unique) key actually can contain any characters. In my sample database there are '/' characters inside the key.

Therefore when requesting a resource from the web api using this route "/api/objects/{objectCode}" if the required objectCode is 1/1 the route should be "/api/objects/1/1" but this results in a page not found exception. And what about when I request a resource on the following route "/api/objects/{objectCode}/subObjects"

  1. does anyone know how I should be working around this problem? Should I be designing around the problem or is there something I can do to allow it?

  2. Also, ideally I'd like to be able to pass an array of these objectCodes but I cannot guarantee that there won't be a , in the objectCode values so the delimiting character would appear in the resource code and thus ServiceStack's delimiter parsing, no?

I have searched for clues already but have only found people asking about encoding in the query string rather than the URI itself.

解决方案

Unfortunately using forward slashes, commas and other unusual characters in the URL will produce undesired results and obviously isn't easy to work with in your routes. But it is possible to work around this by encoding the Id values.

We can use ServiceStack's great flexibility of filters to make encoding and decoding of the values completely transparent to your existing ServiceStack Service.

Transparent Encoding/Decoding Complex Id value

This method will use a Request and Response filter attribute:

  • The Request filter will be responsible for decoding any encoded Id values.
  • The Response filter will be responsible for encoding the plain Id value.

So the Id value will always be encoded in transit, and completely decoded in your Server-side Service implementation.

Full Source Code Here

In my example I have used base64 encoding. But you can substitute this for any encoding you want. For example you may choose to simply convert forward slashes to an underscore.

The attribute that does the encoding and decoding:

public class UsesEncodedAttribute : Attribute, IHasRequestFilter, IHasResponseFilter
{
    IHasRequestFilter IHasRequestFilter.Copy()
    {
        return this;
    }

    IHasResponseFilter IHasResponseFilter.Copy()
    {
        return this;
    }

    public void RequestFilter(IRequest req, IResponse res, object requestDto)
    {
        // Decode the properties on the requestDto having the EncodedId attribute
        var type = requestDto.GetType();
        var properties = type.GetPublicProperties();
        foreach(var p in properties)
        {
            // Find the property marked with EncodedId that is of type string, that can be read and written to
            if(!p.HasAttribute<EncodedIdAttribute>() || p.PropertyType != typeof(string) || !p.CanRead || !p.CanWrite)
                continue;

            // Get the encoded value
            string encodedValue = p.GetValue(requestDto, null) as string;
            if(encodedValue != null)
            {
                // Decode the value from base64
                string decodedValue = Encoding.UTF8.GetString(Convert.FromBase64String(encodedValue));

                // Set the value to decoded string
                p.SetValue(requestDto, decodedValue, null);
            }
        }
    }

    public void ResponseFilter(IRequest req, IResponse res, object response)
    {
        // Encode properties on the response having the EncodedId attribute
        var type = response.GetType();
        var properties = type.GetPublicProperties();
        foreach(var p in properties)
        {
            // Find the property marked with EncodedId that is of type string, that can be read and written to
            if(!p.HasAttribute<EncodedIdAttribute>() || p.PropertyType != typeof(string) || !p.CanRead || !p.CanWrite)
                continue;

            // Get the decoded value
            string decodedValue = p.GetValue(response, null) as string;
            if(decodedValue != null)
            {
                // Encode the value to base64
                string encodedValue = Convert.ToBase64String(decodedValue.ToUtf8Bytes());

                // Set the value to decoded string
                p.SetValue(response, encodedValue, null);
            }
        }
    }

    // The lowest priority means it will run first, before your other filters
    public int Priority { get { return int.MinValue; } }
}

A simple attribute to mark the properties that need Encoding/Decoding:

public class EncodedIdAttribute : Attribute { }

Usage:

Simply add a [UsesEncodedAttribute] attribute to your request and response DTOs that have an encoded Id value. Then mark the properties that require encoding/decoding with the [EncodedId] attribute. Note you can mark multiple properties with this attribute, useful if you have foreign keys.

[UsesEncodedAttribute]
[Route("/Object/{Id}","GET")]
public class GetObjectWithComplexIdRequest : IReturn<ObjectWithComplexIdResponse>
{
    [EncodedId]
    public string Id { get; set; }
}

[UsesEncodedAttribute]
public class ObjectWithComplexIdResponse
{
    [EncodedId]
    public string Id { get; set; }
}

public class ComplexIdTestService : Service
{
    public ObjectWithComplexIdResponse Get(GetObjectWithComplexIdRequest request)
    {
        Console.WriteLine("The requested id is {0}", request.Id);
        return new ObjectWithComplexIdResponse { Id = request.Id };
    }
}

Output:

When we navigate to localhost:8081/Object/SGVsbG8vV29ybGQsVGVzdA== we see in the console that accessing the Id property on our request DTO yields the original decoded Id value of Hello/World,Test. It is notable that the plain Id that we add to the response, is automatically encoded in the reply.

Had we returned:

return new ObjectWithComplexIdResponse { Id = "Another/Complex/Id:Test" }

then the response to the client would have been

{ "Id": "QW5vdGhlci9Db21wbGV4L0lkOlRlc3Q=" }


Edit - Added support for array of Ids:

Use the linked code below to allow collections of encoded Ids to be sent or received.

Full Source Code - With support for array of Ids

For example: http://localhost:8081/Object/SGVsbG8vU29tZXRoaW5nL0Nvb2w=,VGhpcy9Jcy9BLVRlc3Q6SWQ=

[UsesEncodedAttribute]
[Route("/Object/{Ids}","GET")]
public class GetObjectWithComplexIdRequest : IReturn<ObjectWithComplexIdResponse>
{
    [EncodedId]
    public string[] Ids { get; set; }
}

[UsesEncodedAttribute]
public class ObjectWithComplexIdResponse
{
    [EncodedId]
    public string[] Ids { get; set; }
}

这篇关于servicestack在uri中传递斜杠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆