Skip to content

Instantly share code, notes, and snippets.

@puryfury
Last active December 17, 2015 10:58
Show Gist options
  • Select an option

  • Save puryfury/5598613 to your computer and use it in GitHub Desktop.

Select an option

Save puryfury/5598613 to your computer and use it in GitHub Desktop.
Nancy Attrubute-Driven Module Example
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web;
using Nancy;
namespace Nancy
{
/// <summary>
/// Nancy Attribute Driver Module (Must inherit)
/// </summary>
public abstract class NancyAttributeModule : NancyModule
{
/// <summary>
/// If true, Strict Method check and throws Exception. otherwise, ignore it if not valid.
/// </summary>
protected bool IsStrict = true;
/// <summary>
/// Class Base Route Path
/// </summary>
protected readonly string basePath;
public NancyAttributeModule()
: base()
{
this.basePath = string.Empty;
Init();
}
public NancyAttributeModule(string path)
: base(path)
{
this.basePath = path;
Init();
}
private void Init()
{
Type type = this.GetType(), nct = typeof(NancyContext);
Type tattr = typeof(NancyRequestAttribute), battr = typeof(NancyBeforeFilterAttribute), aattr = typeof(NancyAfterFilterAttribute);
MethodInfo[] methods = type.GetMethods();
foreach (MethodInfo method in methods)
{
string strE = "'" + type.FullName + "." + method.Name + "' method {0}";
Exception arglenE = new TargetParameterCountException(string.Format(strE, "must have 1 argument.")),
ncE = new InvalidCastException(string.Format(strE, "must have 1 argument as Nancy.NancyContext!"));
try
{
if (method.IsDefined(tattr, false))
{
ParameterInfo[] ps = method.GetParameters();
if (ps.Length != 1) throw arglenE;
if (method.ReturnType == typeof(void)) throw new InvalidCastException(string.Format(strE, "must have return any type!"));
foreach (NancyRequestAttribute attr in method.GetCustomAttributes(tattr, false))
{
if (attr == null) continue;
ParameterExpression pex = Expression.Parameter(typeof(object));
Func<dynamic, dynamic> body = Expression.Lambda<Func<dynamic, dynamic>>(Expression.Call(Expression.Constant(this), method, pex), pex).Compile();
switch (attr.Type)
{
case RequestType.Get: Get[attr.Path] = body; break;
case RequestType.Post: Post[attr.Path] = body; break;
case RequestType.Put: Put[attr.Path] = body; break;
case RequestType.Delete: Delete[attr.Path] = body; break;
case RequestType.Options: Options[attr.Path] = body; break;
case RequestType.Patch: Patch[attr.Path] = body; break;
}
}
}
else if (method.IsDefined(battr, false))
{
ParameterInfo[] ps = method.GetParameters();
if (ps.Length != 1) throw arglenE;
if (!ps.All(param => param.ParameterType == nct)) throw ncE;
if (method.ReturnType != typeof(Response)) throw new MethodAccessException(string.Format(strE, "must return Nancy.Response!"));
ParameterExpression pex = Expression.Parameter(nct);
BeforePipeline body = Expression.Lambda<Func<NancyContext, Response>>(Expression.Call(Expression.Constant(this), method, pex), pex).Compile();
Before += body;
}
else if (method.IsDefined(aattr, false))
{
ParameterInfo[] ps = method.GetParameters();
if (ps.Length != 1) throw arglenE;
if (!ps.All(param => param.ParameterType == nct)) throw ncE;
if (method.ReturnType != typeof(void)) throw new MethodAccessException(string.Format(strE, "must return NOTHING(void)!"));
ParameterExpression pex = Expression.Parameter(nct);
AfterPipeline body = Expression.Lambda<Action<NancyContext>>(Expression.Call(Expression.Constant(this), method, pex), pex).Compile();
After += body;
}
}
catch (Exception E)
{
if (IsStrict) throw new InvalidOperationException("Attribute-Driven Module Initialization failed.", E);
}
}
//DriverModule Helper ViewBag
After += cx =>
{
ViewBag.ClassName = this.GetType().Name;
ViewBag.BasePath = this.basePath;
};
}
}
/// <summary>
/// Nancy Request Attribute (Can't Inherit with this.)
/// </summary>
[AttributeUsage(AttributeTargets.Method,AllowMultiple=true,Inherited=false)]
public sealed class NancyRequestAttribute : Attribute
{
RequestType type;
string path;
/// <summary>
/// Defines Request for declared request type and route path.
/// </summary>
/// <param name="type"></param>
/// <param name="path"></param>
public NancyRequestAttribute(RequestType type, string path)
{
this.type = type;
this.path = path;
}
/// <summary>
/// Defines Request for GET type and route path.
/// </summary>
/// <param name="path"></param>
public NancyRequestAttribute(string path) : this(RequestType.Get, path) { }
public RequestType Type { get { return type; } }
public string Path { get { return path; } }
}
/// <summary>
/// Nancy Before Filter Attribute
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class NancyBeforeFilterAttribute : Attribute { }
/// <summary>
/// Nancy After Filter Attribute
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class NancyAfterFilterAttribute : Attribute { }
/// <summary>
/// Nancy Request Types for Request Attribute
/// </summary>
public enum RequestType
{
Get,
Post,
Put,
Delete,
Patch,
Options
}
}
using Nancy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using CustomerWanso.Secutiry;
namespace CustomerWanso.Controller
{
public class MainModule : NancySecurityModule
{
[NancyRequest("/")]
public dynamic GetMain(dynamic route)
{
return View["Main.cshtml"];
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Nancy;
using Nancy.Responses;
using CustomerWanso.DataModel;
namespace CustomerWanso.Secutiry
{
public class NancySecurityModule : NancyAttributeModule
{
public const string LOGINURL = "/Login";
public const string USERSESS = "USER";
public NancySecurityModule() : base() { }
public NancySecurityModule(string path) : base(path) { }
[NancyBeforeFilter]
public Response LoginFilter(NancyContext context)
{
Response res = null;
if (context.Request.Session[USERSESS] as UserDto == null)
return new RedirectResponse(LOGINURL);
return res;
}
[NancyAfterFilter]
public void UserInfoFilter(NancyContext context)
{
UserDto user = Session[USERSESS] as UserDto;
if (user != null)
{
ViewBag.UserId = user.UserId;
ViewBag.UserName = user.UserName;
ViewBag.Status = user.Status;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment