Skip to content

Commit

Permalink
Sync latest changes
Browse files Browse the repository at this point in the history
  • Loading branch information
itadapter committed Feb 16, 2016
1 parent 5a30d76 commit 22d1218
Show file tree
Hide file tree
Showing 27 changed files with 842 additions and 88 deletions.
33 changes: 6 additions & 27 deletions Source/NFX.Wave/MVC/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace NFX.Wave.MVC
/// <summary>
/// Decorates MVC Actions
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public class ActionAttribute : Attribute
{
public ActionAttribute()
Expand Down Expand Up @@ -131,43 +131,23 @@ public IEnumerable<WorkMatch> Matches
/// <summary>
/// General ancestor for MVC Action Filters - get invoked before and after actions
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public abstract class ActionFilterAttribute : Attribute
{
public ActionFilterAttribute()
protected ActionFilterAttribute()
{

}

public ActionFilterAttribute(int order)
protected ActionFilterAttribute(int order)
{
m_Name = Guid.NewGuid().ToString();
m_Order =order;
Order =order;
}


/// <summary>
/// Specifies name override
/// </summary>
public ActionFilterAttribute(string name, int order)
{
m_Name = name;
if (m_Name.IsNullOrWhiteSpace()) m_Name = Guid.NewGuid().ToString();
m_Order = order;
}

private string m_Name;
private int m_Order;

/// <summary>
/// Specifies the name of filter
/// </summary>
public string Name{get{return m_Name;}}

/// <summary>
/// Dictates the call order
/// </summary>
public int Order{get{return m_Order;}}
public readonly int Order;

/// <summary>
/// Override to add logic/filtering right before the invocation of action method.
Expand All @@ -180,7 +160,6 @@ public ActionFilterAttribute(string name, int order)
/// Override to add logic/filtering right after the invocation of action method. Must return TRUE to stop processing chain
/// </summary>
protected internal abstract bool AfterActionInvocation(Controller controller, WorkContext work, string action, MethodInfo method, object[] args, ref object result);

}


Expand Down
60 changes: 49 additions & 11 deletions Source/NFX.Wave/MVC/Controller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,30 +56,54 @@ protected internal virtual MethodInfo FindMatchingAction(WorkContext work, strin
}


private static Dictionary<MethodInfo, ActionFilterAttribute[]> m_Filters;
private static Dictionary<Type, ActionFilterAttribute[]> m_ClassFilters;
private static Dictionary<MethodInfo, ActionFilterAttribute[]> m_MethodFilters;

/// <summary>
/// Returns cached (for performance)ordered array of ActionFilterAttributes for type
/// </summary>
protected static ActionFilterAttribute[] GetActionFilters(Type tp)
{
var dict = m_ClassFilters;//thread safe copy
ActionFilterAttribute[] filters = null;

if (dict!=null && dict.TryGetValue(tp, out filters)) return filters;

filters = tp.GetCustomAttributes().Where(atr => typeof(ActionFilterAttribute).IsAssignableFrom(atr.GetType()))
.Cast<ActionFilterAttribute>()
.OrderBy(a => a.Order)
.ToArray();

var newDict = dict!=null ? new Dictionary<Type, ActionFilterAttribute[]>( dict ) : new Dictionary<Type, ActionFilterAttribute[]>();
newDict[tp] = filters;

m_ClassFilters = newDict; //thread safe swap

return filters;
}


/// <summary>
/// Returns cached (for performance)ordered array of ActionFilterAttributes
/// Returns cached (for performance)ordered array of ActionFilterAttributes for action method
/// </summary>
protected static ActionFilterAttribute[] GetActionFilters(MethodInfo mi)
{
var dict = m_Filters;//thread safe copy
ActionFilterAttribute[] actions = null;
var dict = m_MethodFilters;//thread safe copy
ActionFilterAttribute[] filters = null;

if (dict!=null && dict.TryGetValue(mi, out actions)) return actions;
if (dict!=null && dict.TryGetValue(mi, out filters)) return filters;

actions = mi.GetCustomAttributes().Where(atr => typeof(ActionFilterAttribute).IsAssignableFrom(atr.GetType()))
filters = mi.GetCustomAttributes().Where(atr => typeof(ActionFilterAttribute).IsAssignableFrom(atr.GetType()))
.Cast<ActionFilterAttribute>()
.OrderBy(a => a.Order)
.ToArray();

var newDict = dict!=null ? new Dictionary<MethodInfo, ActionFilterAttribute[]>( dict ) : new Dictionary<MethodInfo, ActionFilterAttribute[]>();
newDict[mi] = actions;
newDict[mi] = filters;

m_Filters = newDict; //thread safe swap
m_MethodFilters = newDict; //thread safe swap

return actions;
return filters;
}


Expand All @@ -92,7 +116,14 @@ protected static ActionFilterAttribute[] GetActionFilters(MethodInfo mi)
/// </summary>
protected internal virtual bool BeforeActionInvocation(WorkContext work, string action, MethodInfo method, object[] args, ref object result)
{
var filters = GetActionFilters(method);
//1 Class-level
var filters = GetActionFilters(GetType());
if (filters!=null)
for(var i=0; i<filters.Length; i++)
if (filters[i].BeforeActionInvocation(this, work, action, method, args, ref result)) return true;

//2 Method Level
filters = GetActionFilters(method);
if (filters!=null)
for(var i=0; i<filters.Length; i++)
if (filters[i].BeforeActionInvocation(this, work, action, method, args, ref result)) return true;
Expand All @@ -107,8 +138,15 @@ protected internal virtual bool BeforeActionInvocation(WorkContext work, string
/// </summary>
protected internal virtual object AfterActionInvocation(WorkContext work, string action, MethodInfo method, object[] args, object result)
{
//1 Method Level
var filters = GetActionFilters(method);
if (filters!=null)
if (filters!=null)
for(var i=filters.Length-1; i>=0; i--)
if (filters[i].AfterActionInvocation(this, work, action, method, args, ref result)) return result;

//2 Class Level
filters = GetActionFilters(GetType());
if (filters!=null)
for(var i=filters.Length-1; i>=0; i--)
if (filters[i].AfterActionInvocation(this, work, action, method, args, ref result)) return result;

Expand Down
40 changes: 40 additions & 0 deletions Source/NFX.Wave/MVC/NoCacheAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace NFX.Wave.MVC
{
/// <summary>
/// Decorates controller classes or actions that set NoCache headers in response. By default Force = true
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class NoCacheAttribute : ActionFilterAttribute
{
public NoCacheAttribute() : base(0)
{
Force = true;
}

public NoCacheAttribute(bool force, int order) : base(order)
{
Force = force;
}

public bool Force{ get; private set; }


protected internal override bool BeforeActionInvocation(Controller controller, WorkContext work, string action, MethodInfo method, object[] args, ref object result)
{
return false;
}

protected internal override bool AfterActionInvocation(Controller controller, WorkContext work, string action, MethodInfo method, object[] args, ref object result)
{
work.Response.SetNoCacheHeaders(Force);
return false;
}
}
}
9 changes: 5 additions & 4 deletions Source/NFX.Wave/MVC/SessionCSRFCheckAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@
namespace NFX.Wave.MVC
{
/// <summary>
/// Decorates controller actions that need to check CSRF token against the user session
/// Decorates controller classes or actions that need to check CSRF token against the user session
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class SessionCSRFCheckAttribute : ActionFilterAttribute
{
public const string DEFAULT_TOKEN_NAME = "token";


public SessionCSRFCheckAttribute()
public SessionCSRFCheckAttribute() : base(0)
{
TokenName = DEFAULT_TOKEN_NAME;
}

public SessionCSRFCheckAttribute(string tokenName) : this(tokenName, true)
public SessionCSRFCheckAttribute(string tokenName) : this(tokenName, true, 0)
{
}

public SessionCSRFCheckAttribute(string tokenName, bool onlyExistingSession)
public SessionCSRFCheckAttribute(string tokenName, bool onlyExistingSession, int order) : base(order)
{
TokenName = tokenName;

Expand Down
1 change: 1 addition & 0 deletions Source/NFX.Wave/NFX.Wave.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<Compile Include="MVC\ActionResult.cs" />
<Compile Include="MVC\Attributes.cs" />
<Compile Include="MVC\Controller.cs" />
<Compile Include="MVC\NoCacheAttribute.cs" />
<Compile Include="MVC\Reflection.cs" />
<Compile Include="MVC\SessionCSRFCheckAttribute.cs" />
<Compile Include="Portal.cs" />
Expand Down
10 changes: 8 additions & 2 deletions Source/NFX.Wave/Response.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,14 +368,20 @@ public void AppendCookie(Cookie cookie)
}

/// <summary>
/// Sets headers so all downstream, layers (browsers, proxies) do not cache response
/// Sets headers so all downstream, layers (browsers, proxies) do not cache response.
/// If Force==true(default) then overrides existing headers with no cache.
/// Returns true when headers were set
/// </summary>
public void SetNoCacheHeaders()
public bool SetNoCacheHeaders(bool force = true)
{
if (!force && m_NetResponse.Headers[HttpResponseHeader.CacheControl].IsNotNullOrWhiteSpace())
return false;

m_NetResponse.Headers[HttpResponseHeader.CacheControl] = "no-cache, no-store, must-revalidate";
m_NetResponse.Headers[HttpResponseHeader.Pragma] = "no-cache";
m_NetResponse.Headers[HttpResponseHeader.Expires] = "0";
m_NetResponse.Headers[HttpResponseHeader.Vary] = "*";
return true;
}

/// <summary>
Expand Down
3 changes: 2 additions & 1 deletion Source/NFX.Web/Social/SocialNetwork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ public static bool IsSpecificSocialNetBotUserAgent(SocialNetID net, string userA

if (net == SocialNetID.UNS || net == SocialNetID.VKT)
{
if (userAgent.IndexOf("vkShare; +vk.com/dev/Share", StringComparison.OrdinalIgnoreCase) != -1)
if (userAgent.IndexOf("vkShare;", StringComparison.OrdinalIgnoreCase) != -1 &&
userAgent.IndexOf(@"vk.com/dev/Share", StringComparison.OrdinalIgnoreCase) != -1)
return true;
}

Expand Down
8 changes: 8 additions & 0 deletions Source/NFX/ApplicationModel/CommonApplicationLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public abstract class CommonApplicationLogic : DisposableObject, IApplication
public const string CONFIG_SWITCH = "config";

public const string CONFIG_APP_NAME_ATTR = "application-name";
public const string CONFIG_UNIT_TEST_ATTR = "unit-test";

public const string CONFIG_MEMORY_MANAGEMENT_SECTION = "memory-management";

Expand Down Expand Up @@ -130,6 +131,13 @@ protected override void Destructor()

#region IApplication Members


public bool IsUnitTest
{
get{ return m_ConfigRoot.AttrByName(CONFIG_UNIT_TEST_ATTR).ValueAsBool(); }
}


/// <summary>
/// Returns unique identifier of this running instance
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions Source/NFX/ApplicationModel/IApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ namespace NFX.ApplicationModel
/// </summary>
public interface IApplication : INamed, ILocalizedTimeProvider
{
/// <summary>
/// True if app is launched as a unit test as set by the app config "unit-test=true"
/// The general use of this flag is discouraged as code cnstructs should not form special cases just for unit testing,
/// however in some cases this flag is usefull. It is not exposed via App. static accessors
/// </summary>
bool IsUnitTest{ get;}

/// <summary>
/// Returns unique identifier of this running instance
Expand Down
2 changes: 2 additions & 0 deletions Source/NFX/ApplicationModel/NOPApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ public static NOPApplication Instance
#region IApplication Members


public bool IsUnitTest{ get{ return false;}}

public Guid InstanceID
{
get { return m_InstanceID; }
Expand Down
1 change: 1 addition & 0 deletions Source/NFX/ApplicationModel/TestApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public TestApplication(ConfigSectionNode cfgRoot = null)
ApplicationModel.ExecutionContext.__SetApplicationLevelContext(this, null, null, NOPSession.Instance);
}

public virtual bool IsUnitTest { get; set; }

public virtual Guid InstanceID { get { return m_InstanceID;}}

Expand Down
3 changes: 2 additions & 1 deletion Source/NFX/DataAccess/CRUD/Row.cs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ public string GetDisplayFieldValue(string targetName, int fieldIndex)
private string getDisplayFieldValue(string targetName, Schema.FieldDef fdef)
{
var value = GetFieldValue(fdef);
if (value==null) return null;

var atr = fdef[targetName];
if (atr==null || atr.DisplayFormat.IsNullOrWhiteSpace())
Expand Down Expand Up @@ -576,7 +577,7 @@ protected virtual Exception ValidateField(string targetName, Schema.FieldDef fd

if (atr.MinLength>0)
if (value.ToString().Length<atr.MinLength)
return new CRUDFieldValidationException(Schema.Name, fdef.Name, StringConsts.CRUD_FIELD_VALUE_MAX_LENGTH_ERROR);
return new CRUDFieldValidationException(Schema.Name, fdef.Name, StringConsts.CRUD_FIELD_VALUE_MIN_LENGTH_ERROR);

if (atr.MaxLength>0)
if (value.ToString().Length>atr.MaxLength)
Expand Down
22 changes: 3 additions & 19 deletions Source/NFX/Erlang/Connect/Transport/ErlTransportPasswordSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static class ErlTransportPasswordSource
#region Fields

private static Dictionary<ErlPasswordSession, ErlPasswordSession> s_PassCache =
new Dictionary<ErlPasswordSession, ErlPasswordSession>();
new Dictionary<ErlPasswordSession, ErlPasswordSession>();

#endregion

Expand All @@ -39,7 +39,7 @@ public static class ErlTransportPasswordSource
/// <summary>
/// Returns password for specified userName and nodeName
/// </summary>
public static string GetPassword(object sender, string nodeName, string userName)
public static SecureString GetPassword(object sender, string nodeName, string userName)
{
ErlPasswordSession res = null;
var inCache = false;
Expand All @@ -54,7 +54,7 @@ public static string GetPassword(object sender, string nodeName, string userName
PasswordRequired(res);

if (res.Password != null)
return SecureStringToString(res.Password);
return res.Password;
}

throw new ErlException("Password session not started for {0} user {1}".Args(nodeName, userName));
Expand Down Expand Up @@ -95,22 +95,6 @@ internal static void FinishPasswordSession(ErlPasswordSession ps)
}

#endregion

#region Private

private static string SecureStringToString(SecureString value)
{
if (value == null)
return null;

// Alternative: new System.Net.NetworkCredential(string.Empty, GetPassword()).Password
var bstr = Marshal.SecureStringToBSTR(value);

try { return Marshal.PtrToStringBSTR(bstr); }
finally { Marshal.FreeBSTR(bstr); }
}

#endregion
}

/// <summary>
Expand Down
Loading

0 comments on commit 22d1218

Please sign in to comment.