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 !!
Related
I'm trying to pass some data values from my shared project for access via an iOS AppDelegate.cs method. I don't want to go into too much detail here, as I don't want to limit the reach of this question. But the Method could be called at any point and is used to gain state information about the app, e.g. isLoggedIn etc.
We're using GalaSoft.MvvmLight.Ioc.SimpleIoc and have a CustomViewModelbase, but that probably not too relevant.
The values are mostly part of our CustomViewModelbase, I thought I could create some kind of global object on App.Xaml.cs, which would be accessibily in AppDelegate.cs
Here's what I have...
using GalaSoft.MvvmLight.Ioc;
using ourapp.DTO;
using ourapp.Interfaces;
using ourapp.ViewModels;
namespace ourapp.Helpers
{
public class UITestingHelper : CustomViewModelBase, IUITestingHelper
{
[PreferredConstructor]
public UITestingHelper(
ICustomNavigationService navigationService,
IApiClient apiClient,
IDependencyService dependencyService)
: base(
navigationService,
apiClient,
dependencyService)
{
}
//
UITestingBackdoor _status;
public UITestingBackdoor Status
{
get
{
//var vm = (CustomViewModelBase)App.ViewModelLocator.Resolve(
// typeof(CustomViewModelBase));
_status = new UITestingBackdoor()
{
WillShowAccountPopup = base.HasMoreThanOneAccount,
AppUpdateAvailable = base.AppUpdateAvailable,
IsLoggedIn = App.IsLoggedIn,
IsConnected = App.Connectivity.IsConnected,
};
return _status;
}
}
public string GetAppStatus()
{
string json = Newtonsoft.Json.JsonConvert
.SerializeObject(Status);
return json;
}
}
}
Here's my AppDelegate.cs method...
[Export("UITestBackDoor:")]
public NSString UITestBackDoor(NSString value)
{
var status = App.UITestingStatus.GetAppStatus();
return (NSString)status;
}
However, the object is basically a view model in it's own rights and has dependancy injection to initialise it. However, it isn't registered against a specific view and therefore can not be resolved.
My exact issue is that although a property on my CustomViewModelbase is getting it's value set. When the values is accessed in my global object, the value is empty.
I believe this is related to dependancy injection. However, I'm starting to think there must be a simpler solution?
Yes, I will want to do this for Android as well, but first things first.
Create a global variable in App.cs , initialize it in constructor.
Return the value from a public method and access it in iOS project .
Forms App.cs
UITestingHelper helper;
public string GetAppStatus()
{
return helper.UITestingStatus.GetAppStatus;
}
iOS AppDelegate.cs
public NSString UITestBackDoor(NSString value)
{
return (App.Current as App).GetAppStatus();
}
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.
I have a class which shall act as a "model provider". Basically this is what it shall do:
The ModelProvider creates several objects, e.g. a Project and a User. The idea here is that from any part of my application I can call the ModelProvider to get the latest User or Project. Furthermore, from any part of the application I shall be able to push an updated User or Project to the ModelProvider.
Short: The ModelProvider shall be the class hosting the latest instances of User and Project.
DRAFT
class ModelProvider {
private User user;
private Project project;
public ModelProvider() {
this.user = new User();
this.project = new Project();
}
public void SetModel(T model) {
// If 'model' is of type User, do something like: this.user = model;
// If 'model' is of type Project, do something like: this.project = model;
}
public T GetModel(???) {
// Return the requested model. Either:
// return this.user; or
// return this.project;
}
}
However I don't know how to actually get and set the requested model. Any help is appreciated :-)
It looks strange what you are trying to do. A potentially better way is to provide designated methods, but that depends on what you are actually trying to achieve:
void SetUser(User user)
User GetUser()
void SetProject(Project project)
Project GetProject()
You could make it a generic class:
class ModelProvider<T> // (optionally) where T: baseClassOfUserAndProject
{
private T model;
public void SetModel(T model)
{
this.model = model;
}
public T GetModel()
{
return this.model;
}
}
We have a third party control that is posting the same form parameters twice. We would like to patch the problem for now and notify them so we can continue using their controls. How do you modify a form parameter that is posted to an MVC controller's action method?
public ActionResult Index()
{
var httpParams = this.HttpContext.Request.Params;
if (httpParams["form_element"] != null ) {
httpParams["form_element"] = "some new value"; // NotSupportedException: Collection is read-only
}
return new CustomActionResult(this);
}
Trying to alter the request parameters does not work - it throws a NotSupportedException. Is there a way to redirect this request or do we need some custom HTTPHandler/Module to support this change? We want to control the request body values before the response is processed.
You cannot modify Request.Params and you should not also. As #Ben mentioned, it will be better if you use parameter or custom ModelBinder if you need to complex binding.
public ActionResult Index(string form_element)
{
if (form_element != null ) {
form_element = "some new value"; // not sure, why u need this. :)
}
return new CustomActionResult(this);
}
Or if you have some reason for not doing so, you can just write a wrapper class for the Params, put the logic inside that class. So, it will be easy to modify after the third party control is fixed.
public class ParamsWrapper
{
private NameValueCollection _collection = new NameValueCollection();
private static ParamsWrapper _instance;
public static ParamsWrapper Instance {
if(_instance == null) {
_instance = new ParamsWrapper(HttpContext.Current.Request.Params);
}
return _instance;
}
public ParamsWrapper(NameValueCollection collection) {
// added un-duplicated items to _collection from collection;
}
// put other methods that you want to interact
// for example,
public string this[string name] {
get {
return _collection[name];
}
}
}
In your action methods or other place,
public ActionResult Index()
{
var httpParams = ParamsWrapper.Instance;
return new CustomActionResult(this);
}
Hope it can help.
Thanks for your help, but I gave up on the issue - as it appears there is no possible way to achieve it. I decided to just fix the issue by removing the duplicate form elements before submitting the form using jQuery on the client.
I'm writing a project in c# asp.net mvc3, and I have a helper-class that looks like this:
using System.Collections.Generic;
using System.Web;
namespace CoPrice.Helpers
{
public static class Messages
{
public static IList<Message> All
{
get
{
var list = ((IList<Message>)HttpContext.Current.Session["_messages"]) ?? new List<Message>();
HttpContext.Current.Session["_messages"] = new List<Message>();
return list;
}
}
public static bool Exists
{
get
{
return (((IList<Message>)HttpContext.Current.Session["_messages"]) ?? new List<Message>()).Count > 0;
}
}
public static void Add(MessageType type, string message)
{
Message m = new Message
{
Type = type,
Text = message
};
HttpContext.Current.Session["_messages"] = HttpContext.Current.Session["_messages"] as List<Message> ?? new List<Message>();
((IList<Message>)HttpContext.Current.Session["_messages"]).Add(m);
}
public enum MessageType
{
Info,
Success,
Error
}
public struct Message
{
public MessageType Type;
public string Text;
}
}
}
However, when I try to use these in a test, it crashes (cause of HttpContext.Current beeing null). How can I make this work both in tests and in the app itself? I don't mind having to change this class to use something else than HttpContext.Current to access the session, but I want it to have properties as it does, so it can't take the session-object as a parameter.
Any ideas on how to solve this problem?
You need to define an IMessagesProvider and use an DI container to inject the implementation of the IMessagesProvider. In real use you'll have an implementation that uses the ASP.Net session. In test use you'll mostly mock it. BTW, you probably shouldn't have a static Messages class. In fact, IMessagesProvider will probably replace your static Messages class.
Ex:
public class FooController : Controller
{
IMessagesProvider _messages;
public FooController(IMessagesProvider messages)
{
// Your DI container will inject the messages provider automatically.
_messages = messages;
}
public ActionResult Index()
{
ViewData["messages"] = _messages.GetMessages(Session.SessionId);
return View();
}
}
Mind you, this is a very simple example. In fact, you probably want one more class which is the model that drives the view. A quick intro:
public ActionResult Index()
{
var model = PrepareModel(_messages);
return View(model);
}
"PrepareModel" is your very own method that instantiates a new model class, fills it with the necessary data, and then you send it off to your view. It's typical to have one model class per view defined. E.g. you'd have model classes like "SignupFormModel", "DashboardModel", "ChatModel", etc., Doing so allows you to have strongly-typed views as well (a great thing).
You can also implement a mock session object that inherits from HttpSessionStateBase class
#xanadont is right that you need to turn Messages into a normal class. But (and I know this is heresy in some circles) there's no need for a one-off interface and a full-blown DI framework. Just make the methods on your Messages class virtual so you can mock them in your unit-tests, and use constructor injection:
public class FooController : Controller
{
Messages _messages;
// MVC will call this ctor
public FooController() : this(new Messages())
{
}
// call this ctor in your unit-tests with a mock object, testing subclass, etc.
public FooController(Messages messages)
{
_messages = messages;
}
}