SignalR GetHubContext by name - c#

I would like to change this:
var context = GlobalHost.ConnectionManager.GetHubContext<ControlHub>();
context.Clients.All.sentMessage(room, username, message);
to something like this using a variable as part of the call;
var variableHere = "<ControlHub>";
var context = GlobalHost.ConnectionManager.GetHubContext(variableHere)();
context.Clients.All.sentMessage(room, username, message);
I'm having trouble getting this pulled together. I' m thinking reflection or delegate work flow will get me there but have floundered in getting either approach to work.
I am trying to figure out how to insert a variable as part of a method/function call. In C# (specifically a MVC framework)
Any advise or assistance is appreciated.

You don't need reflection here. There is another overload for ConnectionManager.GetHubContext which accepts the hub name as parameter.
You can your code you use the other overload like this:
string hubName = "the hub name";
var context = GlobalHost.ConnectionManager.GetHubContext(hubName);
Just in case you want to extract the hub name based on the type, take a look at how it's being done internally in SignalR source code. If you need a similar functionality, change the below GetHubName extension methods to public extension methods and use it:
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNet.SignalR.Hubs
{
internal static class HubTypeExtensions
{
internal static string GetHubName(this Type type)
{
if (!typeof(IHub).IsAssignableFrom(type))
{
return null;
}
return GetHubAttributeName(type) ?? GetHubTypeName(type);
}
internal static string GetHubAttributeName(this Type type)
{
if (!typeof(IHub).IsAssignableFrom(type))
{
return null;
}
// We can still return null if there is no attribute name
return ReflectionHelper
.GetAttributeValue<HubNameAttribute, string>(type, attr => attr.HubName);
}
private static string GetHubTypeName(Type type)
{
var lastIndexOfBacktick = type.Name.LastIndexOf('`');
if (lastIndexOfBacktick == -1)
{
return type.Name;
}
else
{
return type.Name.Substring(0, lastIndexOfBacktick);
}
}
}
}

Related

Calling a function from another class in C#/.NET MVC App

I'm trying to create better separation of concerns for code reuse in my program, that way I don't have a bloated controller that does all these different things.
for instance, in my application I have a user profile where users can upload a profile pic. If they don't customize their profile pic, I set the default profile pic to an avatar. I do this through a method to check if their profile pic string is null.
I created a folder called HelperMethods and created a class called UserHelperMethods which currently has one function:
namespace HiRatik.Stories.HelperMethods
{
public class UserHelperMethods
{
//checks if the user's profile pic is null and sets it to default pic if it is
public string GetUserProfilePic(ApplicationUser user)
{
if (user.ProfilePic == null)
{
user.ProfilePic = "profile_pic_default.png";
}
return user.ProfilePic;
}
}
}
Now, in the controller, under the controller's folder, I added using HiRatik.Stories.HelperMethods;
and tried to call the public function GetUserProfilePic from the UserController. But I'm getting an error on the implementation. I'd like to be able to place a lot of these general functions related to users in another class like UserHelperMethods to clean up the bulk in the controller, but I'm missing something on the implementation. the using statement at the top is grayed out, so it's not picking up the function call. Any ideas?
You need to add an instance of the helper method class to every class you want to use it in.
UserHelpMethods helper = new UserHelperMethods();
then you can use it as:
helper.GetUserProfilePic(foundUser);
...
help.DoSomethingImportant(foundUser);
You may want to make this into an Extension. Then you will be able to call it like this:
user.GetProfilePic();
The changes you have to do is, to make both your class and method static and have the this keyword before the parameter. Something like
public static class ApplicationUserExtensions
{
//checks if the user's profile pic is null and sets it to default pic if it is
public static string GetProfilePic(this ApplicationUser user)
{
if (user.ProfilePic == null)
{
user.ProfilePic = "profile_pic_default.png";
}
return user.ProfilePic;
}
}
I would consider making these methods static.
namespace HiRatik.Stories.HelperMethods
{
public class UserHelperMethods
{
//checks if the user's profile pic is null and sets it to default pic if it is
public static string GetUserProfilePic(ApplicationUser user)
{
if (user.ProfilePic == null)
{
user.ProfilePic = "profile_pic_default.png";
}
return user.ProfilePic;
}
}
}
If the helper methods don't rely on any state within the UserHelperMethods object, this will make it much easier to call your methods from anywhere, as there is no longer a need to create an instance of the UserHelperMethods type. You can call the method like this.
UserHelperMethods.GetUserProfilePic(foundUser);
just create instance of the class
var myInstance = new UserHelperMethods();
then just use myInstance object to access the functions in UserHelpMethods class
so you can call any function in UserHelpMethods like this
myInstance.FunctionName();
so in your case it will be like
myInstance.GetUserProfilePic(foundUser);
you could update your code to one of the following
A -
namespace HiRatik.Stories.HelperMethods
{
public class UserHelperMethods
{
private static UserHelperMethods _instance = null;
public static UserHelperMethods Instance()
{
if(_instance == null)
{
_instance = new UserHelperMethods();
}
return _instance;
}
//checks if the user's profile pic is null and sets it to default pic if it is
public string GetUserProfilePic(ApplicationUser user)
{
if (user.ProfilePic == null)
{
user.ProfilePic = "profile_pic_default.png";
}
return user.ProfilePic;
}
}
}
and inside your Controller just use call it like this
UserHelperMethods.Instance().GetUserProfilePic(founduser);
Or the easiest way
var helperObj = new UserHelperMethods();
helperObj.GetUserProfilePic(founduser);
the diff you won't need to create instance all the time in diff controllers
I wish this help you !!

ASP.NET is it possible to use Session & HttpContext.Application in a library

I have the following code in a HttpGet method in a Controller
Session["var1"] = "someval1";
HttpContext.Application["var2"] = "someval2";
I wish to put away this code in a library [dll] so that in the library I have
// Inside DLL Library
// namespace MyNS, class MyCl
public void InitVars()
{
Session["var1"] = "someval1";
HttpContext.Application["var2"] = "someval2";
}
And the call this from my controller Get method
// In controller class HttpGet
InitVars();
How do I access the Session & the Application objects in the Library
I get the errors
The name Session does not exist in the current context
The name HttpContext does not exist in the current context
How can this be done?
You just need to open up the code library .csproj in Visual Studio and set a reference to System.Web.dll and the same code will work in the DLL.
You can get a reference to the current HttpContext using the following code:
var context = System.Web.HttpContext.Current;
after which you can simply call
context.Session["var1"] = "someval1";
context.Application["var2"] = "someval2";
This works
void InitLogin(System.Web.HttpSessionStateBase Session,
System.Web.HttpApplicationStateBase Application)
{
Session["var1"] = "someval1";
Application["var2"] = "someval2";
}
and call it as
InitVars(Session, Application);
How do I access the Session & the Application objects in the Library
Don't do it directly, you'll couple your code. I recommend using the Adapter Pattern. Something like this (untested):
Class Library:
public interface IStorage
{
T GetSession<T>(string key);
void SetSession<T>(string key, T value);
T GetGlobal<T>(string key);
void SetGlobal<T>(string key, T value);
}
public void InitVars(IStorage storage)
{
storage.SetSession("var1", "someval1");
storage.SetGlobal("var2", "somval2");
}
Web App:
public class WebStorage : IStorage
{
public T GetSession<T>(string key)
{
var result = Session[key] as T;
return result;
}
public void SetSession<T>(string key, T value)
{
Session[key] = value;
}
// etc with Global
}
InitVars(new WebStorage);
Now you have no dependencies on any web classes. If down the road you decide to use asp.net core (which has no HttpContext.Current etc etc) you can easily modify your WebStorage class without having to change your class library.

c# MVC + Reflexion: Exposing assembly name

So I have Web app project that refers class library.
Like so:
MyWebApp
DatatableLibrary
----- MyDataTableClass.cs
In my view, I'm making an ajax call that got exposed MyDataTableClass AssemblyQualifiedName. for ex.:
DatatableLibrary.MyDataTableClass, DatatableLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Why? So I can in controller do this trick:
public JsonResult DatatableRequest(string className){ Type.GetType(className); //more stuff + response}
I feel that there is good risk of exposing valuable informations in class and assembly name in View, am I right? Is there any trick or workaround here?
About the security, I can only think about 2 options:
[Strong] Have the current user / current session of who is calling the the controller DatatableRequest and check if that user/caller has the permissions to access that assembly.
[Weak] Pass a token to the call, and return a DULL object if the token isn't correct. By DULL I mean an object which is empty or doesn't do anything, or if you want, you can even return a NULL
But, why do you need to do this?
I would choose the first option and implement a filter so I can reuse it in different places if needed.
like this:
Filter
public class ValidateAssemblyAttribute : ActionFilterAttribute
{
public string classNameField = "className";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Get the field through the helper
string className = filterContext.GetValue<string>(classNameField);
// User 2 doesn't have access to xpto.dll
if (Membership.CurrentUserId == 2 && className == "xpto.dll")
AuthorizationHelpers.NoPermissions(filterContext);
base.OnActionExecuting(filterContext); // Execute base
}
}
Helpers
public static class AuthorizationHelpers
{
public static T GetValue<T>(this ActionExecutingContext filterContext, string Field)
{
if (Field != null)
{
// Get the value provider for the given field name
var value = filterContext.Controller.ValueProvider.GetValue(Field);
// If the value provider has an attemped value (value), proceed
if (value != null && !string.IsNullOrEmpty(value.AttemptedValue))
{
// Get the underlying type of the generic parameter and return the true type: [Nullable<
Type underType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
// Get the TypeConvert to change string (AttemptedValue) to `T`.
TypeConverter conv = TypeDescriptor.GetConverter(underType);
// Create an auxiliar variable that will contain the result.
T result = default(T);
// See if the converted can convert the AttemptedValue to `T`
if (conv.IsValid(value.AttemptedValue))
result = (T)conv.ConvertFrom(value.AttemptedValue); // Convert the value
return result;
}
}
// Return the default of the generic type if the field name doesn't exist.
return default(T);
}
public static void NoPermissions(ActionExecutingContext filterContext)
{
// Override the result so it returns another action (No permissions action)
filterContext.Result = new RedirectResult("~/Error/NoPermissions");
}
}
Usage
[ValidateAssembly]
public JsonResult DatatableRequest(string className)
{
Type.GetType(className);
//more stuff + response
}

Can I access custom method attributes with an aspect-oriented approach?

For example: I have a custom attribute class similar to the following:
[System.AttributeUsage(System.AttributeTargets.Method)
]
public class Yeah: System.Attribute
{
public double whatever = 0.0;
}
Now I decorate some method with it like that:
[Yeah(whatever = 2.0)]
void SampleMethod
{
// implementation
}
Is it possible to access the Yeah-attribute through injecting the code via aspects? I would prefer the postsharp framework for AOP but I am also happy with any other solution because I think that there is such a feature in postsharp but only available in the professional edition (mentioned here: PostSharp Blog)
Take a look on NConcern .NET AOP Framework. This is a new open source project on which I actively work.
//define aspect to log method call
public class Logging : IAspect
{
//define method name console log with additional whatever information if defined.
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
//get year attribute
var year = method.GetCustomAttributes(typeof(YearAttribute)).Cast<YearAttribute>().FirstOrDefault();
if (year == null)
{
yield return Advice.Basic.After(() => Console.WriteLine(methode.Name));
}
else //Year attribute is defined, we can add whatever information to log.
{
var whatever = year.whatever;
yield return Advice.Basic.After(() => Console.WriteLine("{0}/whatever={1}", method.Name, whatever));
}
}
}
public class A
{
[Year(whatever = 2.0)]
public void SampleMethod()
{
}
}
//Attach logging to A class.
Aspect.Weave<Logging>(method => method.ReflectedType == typeof(A));
//Call sample method
new A().SampleMethod();
//console : SampleMethod/whatever=2.0
My logging aspect simply write method name when method called. it include whatever information when it is defined.

mocking session variable in unit test using Moles

Method I am unit testing checks for a session variable like
if(Session["somevar"] != null)
{
// rest of the code
}
In my test, not able to get rid of this since Session is null, it's throwing null referrence exception.
To bypass this, I have tried mocking it like below but no luck
System.Web.Moles.MHttpContext.AllInstances.SessionGet = (HttpContext cntx) =>
{ return (HttpSessionState)cntx.Session["somevar"]; }
I even tried method mention here to simulate HttpContext and then doing below
HttpContext.Current = new HttpContext(workerRequest);
HttpContext.Current.Session["somevar"] = value;
But again no luck. This time, though the HttpContext.Current is not null but HttpContext.Current.Session and hence throws null ref exception.
Any idea how can I mock this/by pass this in my test [Without using any external DLL or main code change. Sorry, but can't afford to do so].
Thanks and appreaciate lot your help.
Update 2013:
The bad news now is that the Moles framework was a Microsoft Research (MSR) project, and will not be supported in Visual Studio 2012. The great news is that Microsoft has now integrated the MSR project into the mainline framework as Microsoft Fakes.
I found an article that solves the problem you had, using the Fakes framework instead of the Moles framework:
http://blog.christopheargento.net/2013/02/02/testing-untestable-code-thanks-to-ms-fakes/
Here's an updated version of my previous answer that uses the Fakes framework instead of Moles.
using System.Web.Fakes;
// ...
var sessionState = new Dictionary<string, object>();
ShimHttpContext.CurrentGet = () => new ShimHttpContext();
ShimHttpContext.AllInstances.SessionGet = (o) => new ShimHttpSessionState
{
ItemGetString = (key) =>
{
object result = null;
sessionState.TryGetValue(key, out result);
return result;
}
};
You might even be able to make it look more like the Moles version I posted before, though I haven't tried that out yet. I'm just adapting the article's code to my answer :)
Before 2013 edit:
You said you want to avoid changing the code under test. While I think it should be changed, as directly accessing session state like that is a bad idea, I can understand where you're coming from (I was in test once...).
I found this thread describing how someone moled both HttpContext and HttpSessionState to get around this problem.
Their code ended up looking like this:
MHttpContext.CurrentGet = () => new MHttpContext
{
SessionGet = () => new MHttpSessionState
{
ItemGetString = (key) =>
{
if (key == "some")
return "someString"/* or any other object*/;
else return null;
}
}
};
I'd go even farther and implement ItemGetString with a dictionary:
var sessionState = new Dictionary<string, object>();
MHttpContext.CurrentGet = // ...
{
// ...
ItemGetString = (key) =>
{
object result = null;
sessionState.TryGetValue(key, out result);
return result;
}
Before edit:
I usually solve problems like this by encapsulating global state with an abstract class or interface that can be instanced and mocked out. Then instead of directly accessing the global state, I inject an instance of my abstract class or interface into the code that uses it.
This lets me mock out the global behavior, and makes it so my tests don't depend on or exercise that unrelated behavior.
Here's one way to do that (I'd play with the factoring a bit tho):
public interface ISessionContext
{
object this[string propertyName] { get; set; }
}
public class ServerContext : ISessionContext
{
public object this[string propertyName]
{
get { return HttpContext.Current.Session[propertyName]; }
set { HttpContext.Current.Session[propertyName] = value; }
}
}
public class SomeClassThatUsesSessionState
{
private readonly ISessionContext sessionContext;
public SomeClassThatUsesSessionState(ISessionContext sessionContext)
{
this.sessionContext = sessionContext;
}
public void SomeMethodThatUsesSessionState()
{
string somevar = (string)sessionContext["somevar"];
// todo: do something with somevar
}
}
This would require changes to your code-under-test, but it is the type of change that is good both for testability and for portability of the code.

Categories

Resources