Skip to content

Instantly share code, notes, and snippets.

@scottmcarthur
Created February 9, 2014 13:09
Show Gist options
  • Save scottmcarthur/8898823 to your computer and use it in GitHub Desktop.
Save scottmcarthur/8898823 to your computer and use it in GitHub Desktop.
Transparent Encoded Complex Ids in Request/Response DTO in ServiceStack v4. (With support for string[])
using System;
using ServiceStack;
using System.Text;
using ServiceStack.Web;
using System.Collections.Generic;
namespace ComplexIdTest
{
class MainClass
{
public static void Main()
{
// Very basic console host
var appHost = new AppHost(500);
appHost.Init();
appHost.Start("http://*:8081/");
Console.ReadKey();
}
}
public class AppHost : AppHostHttpListenerPoolBase
{
public AppHost(int poolSize) : base("Complex Id Test Service", poolSize, typeof(ComplexIdTestService).Assembly) {}
public override void Configure(Funq.Container container)
{
Config = new HostConfig {
DebugMode = true,
};
}
}
[UsesEncodedAttribute]
[Route("/Object/{Id}","GET")]
public class GetObjectWithComplexIdRequest : IReturn<ObjectWithComplexIdResponse>
{
[EncodedId]
public string Id { get; set; }
}
[UsesEncodedAttribute]
public class ObjectWithComplexIdResponse
{
[EncodedId]
public string[] Ids { get; set; }
}
public class ComplexIdTestService : Service
{
public ObjectWithComplexIdResponse Get(GetObjectWithComplexIdRequest request)
{
Console.WriteLine("The requested id is {0}", request.Id.Length);
return new ObjectWithComplexIdResponse { Ids = new[] { "Hello/Something/Cool", "This/Is/A-Test:Id" } };
}
}
public class EncodedIdAttribute : Attribute
{
}
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.CanRead || !p.CanWrite)
continue;
// Check if the property is an Array (assume string[]) or simply string
bool isArray = p.PropertyType.BaseType == typeof(Array);
if(!isArray && p.PropertyType != typeof(string))
continue;
// Collections to store the encoded and decoded values
List<string> encodedValues = new List<string>();
List<string> decodedValues = new List<string>();
// Get the value from the DTO
var value = p.GetValue(requestDto, null);
if(value == null)
continue;
// If the value is an array, then add all the values to encoded collection
if(isArray)
encodedValues.AddRange(value as IEnumerable<string>);
else // Value is singular just add one value
encodedValues.Add(value as string);
// Decode all the values
foreach(var encodedValue in encodedValues)
decodedValues.Add(Encoding.UTF8.GetString(Convert.FromBase64String(encodedValue)));
// If it is an array return an array of the decoded values
if(isArray)
p.SetValue(requestDto, decodedValues.ToArray(), null);
else // Value is single string, return the first item
p.SetValue(requestDto, decodedValues[0], 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.CanRead || !p.CanWrite)
continue;
// Check if the property is an Array (assume string[]) or simply string
bool isArray = p.PropertyType.BaseType == typeof(Array);
if(!isArray && p.PropertyType != typeof(string))
continue;
// Collections to store the encoded and decoded values
List<string> encodedValues = new List<string>();
List<string> decodedValues = new List<string>();
// Get the value from the response
var value = p.GetValue(response, null);
if(value == null)
continue;
// If the value is an array, then add all the values to decoded collection
if(isArray)
decodedValues.AddRange(value as IEnumerable<string>);
else // Value is singular just add one value
decodedValues.Add(value as string);
// Encode all the values
foreach(var decodedValue in decodedValues)
encodedValues.Add(Convert.ToBase64String(decodedValue.ToUtf8Bytes()));
// If it is an array return an array of the encoded values
if(isArray)
p.SetValue(response, encodedValues.ToArray(), null);
else // Value is single string, return the first item
p.SetValue(response, encodedValues[0], null);
}
}
public int Priority { get { return int.MinValue; } }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment