servicestack在uri中传递斜杠 [英] servicestack pass forward slash in uri
问题描述
我正在使用servicestack来构建一个web api,通过网络提供一些旧的数据。不幸的是,数据模式对于ServiceStack.Ormlite的标准使用并不是很好。例如,没有主键,在一个表上,(非唯一)键实际上可以包含任何字符。在我的示例数据库中,密钥中有'/'字符。
因此,当使用此路由从web api请求资源时/ api / objects / {objectCode} 如果所需的objectCode为1/1,路由应为/ api / objects / 1/1,但这会导致页面未找到异常。当我在以下路由上请求资源时,怎么办?/ api / objects / {objectCode} / subObjects
-
任何人都知道我应该如何解决这个问题?我应该围绕这个问题进行设计,还是有什么可以做的呢?
-
同样,我希望能够传递一个数组的这些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"
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?
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屋!