Using the subdomain as a parameter - c#

I’ve got an ASP.net MVC (5.2) site that runs using several subdomains, where the name of the subdomain is the name of a client in my database. Basically what I want to do is use the subdomain as a variable within my action methods to allow me to get the correct data from my database.
I did something similar a few years back, but it’s messy and not intuitive, so was wondering if there’s a better way to do it than I was using before. Here’s what I did before:
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
Session["subdomain"] = GetSubDomain(Request.Url);
}
private static string GetSubDomain(Uri url) {
string host = url.Host;
if (host.Split('.').Length > 1) {
int index = host.IndexOf(".");
string subdomain = host.Substring(0, index);
if (subdomain != "www") {
return subdomain;
}
}
return null;
}
Which basically assigned a key to the session variable if the subdomain was anything other than "www", but I’m really not happy with this way of doing it as it relies on me knowing that the session might contain this magic value!
Ideally I’d like to be able to create an attribute that I can decorate my classes/methods with that would extract the subdomain and then allow me to include a "subdomain" parameter in my action method that would contain the value extracted by the attribute. Is that even possible?
If that can’t be done, is there a better way of doing what I’m doing now without having to rely on the session?
Thanks,
Dylan

Your right this doesn't need to be stored in Session and IMHO shouldn't be, I would refactor this out into its own class and use HttpContext.Current.
public interface ISubDomainProvider
{
string SubDomain { get; set; }
}
public class SubDomainProvider : ISubDomainProvider
{
public SubDomainProvider()
{
string host = HttpContext.Current.Request.Url.Host; // not checked (off the top of my head
if (host.Split('.').Length > 1)
{
int index = host.IndexOf(".");
string subdomain = host.Substring(0, index);
if (subdomain != "www")
{
SubDomain = subdomain;
}
}
}
public string SubDomain { get; set; }
}
You choose how to use it, if your using an IoC container it would just be a case of injecting this class into your controller via the constructor, I like this because it is easier to Mock and Unit Test. Of course you can still do this:
public class SomeController : Controller
{
private readonly ISubDomainProvider _subDomainProvider;
public SomeController()
{
_subDomainProvider = new SubDomainProvider();
}
}
You could even create you own abstract Controller Class:
public abstract class MyAbstractController : Controller
{
public MyAbstractController()
{
SubDomain = new SubDomainProvider();
}
protected string SubDomain {get; set; }
}
public class SomeController : MyAbstractController
{
public ActionResult SomeAction()
{
// access the subdomain by calling the base base.SubDomain
}
}

You could set the name in the Session on the Session_Start event in the global.asax, this means it would only happen one time and would persist for the duration of the users' session
public void Session_Start(object sender, EventArgs e)
{
Session["subdomain"] = GetSubDomain(Request.Url);
}

Looks like there’s a good way of doing what I’m after at:
ASP.NET MVC Pass object from Custom Action Filter to Action
It essentially uses the route data to pass a custom parameter to the action, and can also pass objects other than simple strings etc.
On the plus side it avoids using the session and relying on magic values, but on the downside it means processing the URL for every request, which probably isn’t a good idea if a database is involved.

Related

Injecting HttpContext-derived values into some classes

Here is the problem
A multi-layered approach. The end point/action used BLL Provider which must trim data not only using certain business criteria but also security criteria. For example, a super user can view all items and plain user can only view items assigned to his group.
The knee-jerk reaction to this - public IEnumerable<Item> GetItems(int? userId, string color, string location), where if user Id is not provided - get all items. But what if I want to put additional layer of protection - derive query based on a special MyIdentityProvider.
public class BllItemDataProvider : IBllItemDataProvider
{
private IMyIdentityProvider _myIdentity;
public BllItemDataProvider(IMyIdentityProvider myIdentity)
{
_myIdentity = myIdentity;
}
public BllItemDataProvider(IMyIdentityProvider myIdentity)
{
_myIdentity = myIdentity;
}
}
MyIdentityProvider would have userId, isSuperUser, other flags, etc.
The question is, how to wire it up so that in Web API IHttpContextAccessor or the HttpContext will hydrate MyIdentityProvider from the Claims I find in the [controller].HttpContext.User.Claims. So my controller would look like
public class ItemController : ControllerBase
{
private IBllItemDataProvider _prov
public ItemController (IBllItemDataProvider prov)
{
_prov = prov;
}
[HttpGet("[action]/{color}/{location?}")]
public IActionResult SomeItems (string color, string location)
{
_prov = prov.GetItems(color, location);
}
}
Or, I should just create a base controller which can obtain that and inherit from it?
public abstract class ClaimControllerBase: ControllerBase - in constructor parse claims and setup thread principal, which can then be accessed down in the pipeline?
Thanks
Additionally I can add that these flags in the MyIdentityProvider will be taken from HttpContext.User.Claims which in turn come from JWT token and filled by Identity Framework. So, literally, I can take those claims and slap it in the base controller into a thread. But I don't think this a pretty solution.
Alright, looks like this one goes into DIY, or solve it yourself
Added this code
// CREATED Helper
public class MyIdentityProviderHelper
{
public static IMyIdentityProvider FetchProvider(IHttpContextAccessor accessor)
{
var prov = new MyIdentityProvider();
// -- HERE parse claims and fill properties
return prov;
}
}
// ADDED to Startup
services.AddHttpContextAccessor();
services.AddTransient<IMyIdentityProvider>((s) => // factory method is the real secret here
{
return MyIdentityProviderHelper.FetchProvider(
s.GetService<IHttpContextAccessor>());
});
services.AddTransient<IItemProvider, RealItemProvider>();
// DECLARED RealItemProvider
public class RealItemProvider : IItemProvider
{
private IMyIdentityProvider _identity
public RealItemProvider (IMyIdentityProvider identity)
{
_identity = identity;
}
public IEnumerable<Item> GetItems(string color, string location)
{
IEnumerable<Item> items = null;
if (_identity.Roles.Contains(Roles.SysAdmin))
items = GetAllItems(color, location); // private
else
items = GetUserItems(color, location); // private
return items;
}
}
As you see, the main soul saver here is ability to provide a factory for the object and use factory of another object to pass the retrieved object

accessing multi endpoints web services (ASMX) best practices in c#

I have a clean architecture project that provide micro services, one of which is to access Agresso ERP web services.
https://***************/service.svc
it provide many services
https://**/service.svc?FooService/Foo
https://**/service.svc?BooService/Boo
each of which has it's own service reference(connected service), and each of which has many methods.
each call to any of the end point you need to pass credentials with it.
var fooSoapClient = new FooSoapClient();
var credentials = new WSCredentials
{
Username = "fakeuser",
Password = "fakepassword",
Client = "fakeclient",
};
var result = fooSoapClient.GetFoosAsync(Foo filter,true,
credentials );
(P.S) credential class exist in all entities
namespace Foo1NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
namespace Foo2NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
i can access all end points with no problem.
I have the following Questions:
Is there a generic solution i can follow for not to Fall in DRY?
is there a design pattern that best target this issue?
Here is what I've done in the past, it fits in well into Dependency Injection/containers if you use that as well. The key thing here is to define an single interface that all services will implement. Your code that uses this should only be using the interface.
Each class should implement an interface you define, e.g. IWebServiceOperations
public interface IWebServiceOperations
{
WebServiceOperationResult GetFooAsync(WebServiceOperationRequest request);
}
I'll leave you to figure out the classes WebServiceOperationResult/Request, they just hold your request/response variables, including credentials.
Then each webservice you need to implement is done in a separate class. You also dictate in the constructor what type of implementation this is (FooSoap1 vs FooSoap2) e.g.
public class FooSoapClient : BaseClient, IWebServiceOperations
{
public FooSoapClient() : base(Clients.FooSoap1)
public GetFooAsync(...)
{
...
}
}
public class BaseClient
{
private readonly eFooServiceType _serviceType;
public eFooServiceType ServiceType {
get{
return _serviceType;
}
}
protected BaseClient(eFooServiceType service)
{
_serviceType = service;
}
}
Now you should have a bunch of class references. Either your DI container can resolve these for you, based on the service type you want, or you could add them to a Dictionary, so if you wanted to operate against FooSoap1, you'd do...
var fooSoapClient1 = myServices[Clients.FooSoap1];
await fooSoapClient1.GetFooAsync(...)

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 !!

Independent sessions for each tabs C# WebApi / Angular2+

We are building aWeb app that allows users to open different projects they created using this app. The front-end is an Angular 4 app with a REST Architecture and the backend a C# Asp.net Web Api.
Our problem is that we store all our backend datas in a Session (because it's a huge object with mathematical datas and formulas in it), and when we open multiple projects in different tabs, the session become in common between each tabs so it causes interferences.
We are trying to find a way to attach each instance of the app (each project) with an unique session in the server. We look for using GUID stored in window.name for each tab, then sent to the server which has HttpContext.Current.Session["GUIDSessionID"]; that stores our object but we did not find the way to make it work, as we are beginners in c# development.
Here are the links we look for to find a solution (without success) :
http://blog.gauffin.org/2012/02/get-a-unique-session-in-each-browser-tab/
https://www.codeproject.com/Questions/364203/Stop-Sharing-Session-State-between-Multiple-Tabs-o
Thanks in advance.
Nikolas
Generate a unique session id a hash or something.
In Angular to store it can put locale localStorage.setItem('GUIDSessionID', 'YourSessionID');.
If you want to get it even after a refresh localStorage.getItem('GUIDSessionID');
If you login with a new generate new SessionID remove old localStorage.removeItem('GUIDSessionID') and set new.
The easiest way to achieve this is by -
reading the project ID from URL/querystring and put that in some hidden field on the page.
Create all the session variables with key starting that project ID.
For example, if your project ID is '654654481CEG', your session assignment will be something like this:
Session[string.Format("{0}-projectName", "654654481CEG")] = "WhateverYourValueIs";
While reading the value back from session, you will do the same -
string strprojectName = Session[string.Format("{0}-projectName", "654654481CEG")].ToString();
I had the same problem with a coworker and we used sort of sub-sessions:
//We changed this
HttpContext.Current.Session["x"] = x;
HttpContext.Current.Session["y"] = y;
//To this
HttpContext.Current.Session["guid"] = new SessionContent{x = x, y = y };
and we did as follow :
BackEnd
public static class SessionUtils
{
public class SessionContent
{
public XClass xProperty{ get; set; }
public YClass yProperty{ get; set; }
}
public static string GetSessionGUID(IHttpRouteData route)
{
return route.Values["guid"].ToString();
}
public static XClass GetSessionXProperty(HttpContextBase httpContextBase, IHttpRouteData route)
{
return ((SessionUtils.SessionContent)httpContextBase.Session[GetSessionGUID(route)]).xProperty;
}
public static void SetSessionXProperty(HttpContextBase httpContextBase, IHttpRouteData route, XClass xProperty)
{
((SessionUtils.SessionContent)httpContextBase.Session[GetSessionGUID(route)]).xProperty= xProperty;
}
public static YClass GetSessionYProperty(HttpContextBase httpContextBase, IHttpRouteData route)
{
return ((SessionUtils.SessionContent)httpContextBase.Session[GetSessionGUID(route)]).yProperty;
}
public static void SetSessionYProperty(HttpContextBase httpContextBase, IHttpRouteData route, YClass yProperty)
{
((SessionUtils.SessionContent)httpContextBase.Session[GetSessionGUID(route)]).yProperty= yProperty;
}
}
Here is an controller for example:
public class TestController : ApiController
{
private HttpContextBase _httpContext;
public TestController ()
{
_httpContext = new HttpContextWrapper(HttpContext.Current);
}
public AuditTrailController(HttpContextBase context)
{
_httpContext = context;
}
[HttpGet]
[Route("Send}")]
public HttpResponseMessage Send()
{
XClass x = SessionUtils.GetSessionXProperty(_httpContext, Request.GetRouteData());
HttpResponseMessage response = new HttpResponseMessage();
response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(JsonConvert.SerializeObject(x), System.Text.Encoding.UTF8, "application/json");
return response;
}
}
And in Angular front we just generate a GUID, send it to the back end while initiating the project and add it to each request we make.
window.name = UUID.UUID();
Then in services :
return this.http.get(environment.baseUrl + '/' + window.name + '/myController/')
.map(res => res.json());

Why are Controller methods like RedirectToAction() and HttpNotFound() protected internal?

I want to implement a service pattern to provide some logic for several of my ASP.NET MVC controllers. Depending on the result of the logic, I may want the controllers to redirect, or give a 404 not found, or various other responses. Therefore I want my controllers to be able to receive an out ActionResult parameter from the service method(s) that they can return to carry out these responses.
The trouble is that I don't see any way for the service to generate ActionResults. Because methods like RedirectToAction() and HttpNotFound() in the Controller class are set to protected internal, they cannot be accessed from the service class.
What is the rationale behind making them protected internal? How is my service supposed to indicate to the controllers what action result they should return?
An example of what I might want to do is allow the user, in several places, to set a configuration variable if they have permission. The controller code would look something like:
public ActionResult SetVariable(int variableId, int variableValue) {
ActionResult actionRes;
_svcVars.SetVariable(variableId, variableValue, out actionRes);
return actionRes;
}
... and the service code would look something like:
public bool SetVariable(int variableId, int variableValue, out ActionResult actionRes) {
ConfigRepository repoConfig = new ConfigRepository();
if (!repoConfig.VariableExists(variableId)) {
actionRes = HttpNotFound("Could not find config variable");
return false;
}
if (!repoConfig.VariableMayBeChanged(variableId)) {
actionRes = Redirect("/ChangeForbidden.html");
return false;
}
int variablesListId = repoConfig.SetVariable(variableId, variableValue);
actionRes = RedirectToAction("ViewVariablesList", new { listId = variablesListId });
return true;
}
The trouble is that I don't see any way for the service to generate ActionResults.
As with any object in .NET you could use its constructor in order to create an instance.
Just like that:
var values = new RouteValueDictionary(new
{
action = "ViewVariablesList",
listId = variablesListId
});
actionRes = new RedirectToRouteResult(values);
As far as why the corresponding methods on the Controller class are protected and internal, well, a question that you could address to the people designing the framework.

Categories

Resources