I have a custom control in my MVC 5 project. At the end of it I want add on a Save button and a ValidationSummary (in the WriteSubmitControls method). A Validation Summary is built using an instance of a HtmlHelper. Seems like HtmlHelper and AjaxHelper should share a base class or interface, but they don't appear to.
How do I access an instance of HtmlHelper without passing it in?
public class MyCustomAjaxForm: IDisposable
{
private readonly MvcForm _ajaxForm;
public MyCustomAjaxForm(AjaxHelper ajaxHelper)
{
_ajaxForm = ajaxHelper.BeginForm("Save", "Contacts", routeValues, ajaxOptions);
}
private void WriteSubmitControls()
{
_writer.WriteLine("<button type='submit'>Save</button>");
// Output Validation Summary Here
}
public void Dispose()
{
WriteSubmitControls();
_ajaxForm.Dispose();
}
}
I think I found a solution, but not sure if it's the best way. I create a new instance of HtmlHelper using the ViewContext and ViewDataContainer from the AjaxHelper.
public class MyCustomAjaxForm: IDisposable
{
private readonly MvcForm _ajaxForm;
private readonly HtmlHelper _htmlHelper;
public MyCustomAjaxForm(AjaxHelper ajaxHelper)
{
_ajaxForm = ajaxHelper.BeginForm("Save", "Contacts", routeValues, ajaxOptions);
//create instance of HtmlHelper
_htmlHelper = new HtmlHelper(ajaxHelper.ViewContext, ajaxHelper.ViewDataContainer);
}
private void WriteSubmitControls()
{
_writer.WriteLine("<button type='submit'>Save</button>");
//output ValidationSummary using instance of HtmlHelper
_writer.WriteLine(_htmlHelper.ValidationSummary(true));
}
public void Dispose()
{
WriteSubmitControls();
_ajaxForm.Dispose();
}
}
Related
The old controller code with Concrete dependencies:
public SomeController: Controller
{
public SomeController()
{
}
public ActionResult Default()
{
**Something something = new Something(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString());**
something.SomeMethod();
}
}
The new Controller code with TDD focus:
public SomeControllerNew: Controller
{
private readonly ISomething _something;
public SomeControllerNew(ISomething something)
{
_something = something;
}
public ActionResult Default()
{
_something.SomeMethod();
}
}
PROBLEM:
Now in new TDD approach i need to invoke constructor where I am registering the Interface. I have put it in UnityBootstraper common file, Something like:
var container = new UnityContainer();
container.RegisterType();
**Something something = new Something(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString());**
something.SomeMethod();
This is not working here. Error is quite clear:
Object reference required for non-static field, method, property 'System.Web.Mvc.Controller.Request.get'.
I can't figure out how i can access http request here in UnityBootstrapper?
Edit:
Trying to do all this in RegisterRoutes.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
DependencyResolver.SetResolver(new Unity.Mvc3.UnityDependencyResolver(UnityBootstrapper.Initialise()));
var container = new UnityContainer();
container.RegisterType<ISometing, Something>();
}
}
One way to do it is to create an abstract factory like this:
public interface ISomethingFactory
{
ISomething Create(string url);
}
public class SomethingFactory : ISomethingFactory
{
public ISomething Create(string url)
{
return new Something(url);
}
}
And make your controller depend on it like this:
public class SomeControllerNew: Controller
{
private readonly ISomething _something;
public SomeControllerNew(ISomethingFactory somethingFactory)
{
_something = somethingFactory.Create(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString();
}
public ActionResult Default()
{
_something.SomeMethod();
}
}
A better approach (IMO) is to use a custom Controller Factory instead of using the Dependency Resolver like this:
public class CustomFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var request = requestContext.HttpContext.Request; //Here we have access to the request
if (controllerName == "Some") //Name of controller
{
//Use the container to resolve and return the controller.
//When you resolve, you can use ParameterOverride to specify the value of the string dependency that you need to inject into Something
}
return base.CreateController(requestContext, controllerName);
}
}
This way you don't have to introduce the ISomethingFactory, and your controller would still depend on ISomething directly.
You would need to tell the MVC framework about this custom controller factory like this (in Application_Start):
ControllerBuilder.Current.SetControllerFactory(new CustomFactory());
I try to create some Html Helpers which will have an opening tag and closing tag which will include other contents like the Html.BeginForm does.
For example in Razor we can use the Html.BeginForm helper which has the following syntax:
#using (Html.BeginForm())
{
}
This code will include the contents of curly brackets within a and . The only way that I solved opening and closing a tag with contents is by using two html helpers. I define two html helpers:
public static MvcHtmlString StartForm(this System.Web.Mvc.HtmlHelper helper)
{
return new MvcHtmlString("<form>");
}
public static MvcHtmlString EndForm(this System.Web.Mvc.HtmlHelper helper)
{
return new MvcHtmlString("</form>");
}
Then I use the helpers using the following example:
#Html.StartForm()
contents
#Html.EndForm()
But I would like to be able to make one html helper which will have the following format in the view:
#using (Html.MyForm())
{
<text>contents</text>
}
Can someone help me with this problem because I do not know even how to search it.
You can define a class just like the way the MvcForm is implemented. The class below allows you to create a tag which contains other elements.
public class MvcTag : IDisposable
{
private string _tag;
private bool _disposed;
private readonly FormContext _originalFormContext;
private readonly ViewContext _viewContext;
private readonly TextWriter _writer;
public MvcTag(ViewContext viewContext, string tag)
{
if (viewContext == null)
{
throw new ArgumentNullException("viewContext");
}
_viewContext = viewContext;
_writer = viewContext.Writer;
_originalFormContext = viewContext.FormContext;
viewContext.FormContext = new FormContext();
_tag = tag;
Begin(); // opening the tag
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Begin()
{
_writer.Write("<" + _tag + ">");
}
private void End()
{
_writer.Write("</" + _tag + ">");
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
End(); // Closing the tag
if (_viewContext != null)
{
_viewContext.OutputClientValidation();
_viewContext.FormContext = _originalFormContext;
}
}
}
public void EndForm()
{
Dispose(true);
}
}
To make use of this MvcTag in the way the MvcForm is used, we have to define an extension
public static class HtmlHelperExtensions
{
public static MvcTag BeginTag(this HtmlHelper htmlHelper, string tag)
{
return new MvcTag(htmlHelper.ViewContext, tag);
}
}
And that's it. Now you can use it as:
#using(Html.BeginTag("div")) #* This creates a <div>, alternatively, you can create any tag with it ("span", "p" etc.) *#
{
<p>Contents</p>
}
I'm building a custom HtmlHelper for MVC. I'd like to allow the user to add a block of HTML that will be used with the helper. So, I'm planning on having something similar to the following in my view:
#using (Html.MyHelper())
{
// foo
}
The MyHelper helper method is defined similar to the following:
public static MyHelperWriter MyHelper(this HtmlHelper helper)
{
helper.ViewContext.Writer.Write(#"<span>");
return new MyHelperWriter(helper.ViewContext.Writer);
}
public class MyHelperWriter : IDisposable
{
private bool disposed;
public TextWriter Writer { get; set; }
public MyHelperWriter(TextWriter writer)
{
/// TODO: Modify the TextWriter stream
Writer = writer;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
this.disposed = true;
Writer.Write(#"</span>");
}
}
}
What I'd like to do is update the TextWriter stream to capture it and do something to the contents. I know I can flush the stream, but I may want to override the behavior.
If this cannot be done (and seems icky), is there a better way to accomplish this same thing?
Have you looked into delegated razor templates?
I need to find a way to use Ninject in my classes (models) and also in my controllers of my MVC application.
How can I do to use the same bindings in both sides?
Right now I use my generated NinjectWebCommon.cs create my kernel and initialize the bootstrap:
private static void RegisterServices(IKernel kernel)
{
System.Web.Mvc.DependencyResolver.SetResolver(
new WebApplication1.Models.NinjectDependencyResolver(kernel)
);
}
My NinjectDependencyResolver looks like:
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel k;
public NinjectDependencyResolver(IKernel kp)
{
this.k= kp;
AddBindings();
}
public object GetService(Type serviceType)
{
return k.Get(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return k.GetAll(serviceType);
}
private void AddBindings()
{
k.Bind<ISerializer>().To<MySerializer>();
}
}
MySerializer is my serialization class.
For my controllers, this part works fine.
But let's say I have the following model:
public class MyButton
{
ISerializer serializer;
public MyButton(ISerializer weapon)
{
serializer = weapon;
}
public string ToSString()
{
return serializer.serialize("my string - ");
}
}
How can I make Ninject work also for my model?
Thank you!
You may inject the model as well and add the following binding
private void AddBindings()
{
k.Bind<IMySerializer>().To<MySerializer>();
k.Bind<IModel>().To<Model>();
}
or if you are not injecting your model then you could do something like this thread says
using ninject to inject dependency to The Model classes or non-controller classes
I am working on ASP.NET MVC 3 application. I am using Autofac as my dependency resolver.
I have two projects one core and other UI. In the core project I have an interface which holds
information about the logged in user if any. This is inherited in my UI project.
public interface IWebContext
{
User User {get;set}
bool IsLoggedIn {get;}
}
In ui project this is implemented as
public class WebContext : IWebContext
{
//codes here to get user and islogged in proerty.
}
In the core project I am creating link based on some logic.
public static class ButtonExtension
{
public static MvcHtmlString EditButton(this HtmlHelper helper, string controller, string action, object id, string text)
{
var webContext= how to get IWebContext here.
if (!webContext.IsLoggedIn)
{
return MvcHtmlString.Empty;
}
return MvcHtmlString.Create(string.Format("{3}", controller, action, id, text));
}
}
In my global.asax I am registering all my services using IOC static class
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
IOC.Build();
}
here is my IOC class.
public static class IOC
{
private static IContainer _container;
public static void Build()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.Register(c => new WebContext()).As<IWebContext>().SingleInstance();
builder.Register(c => new ImageServiceLocal()).As<IImageService>().InstancePerHttpRequest();
builder.RegisterFilterProvider();
_container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(_container));
}
public static T Resolve<T>()
{
if (_container == null)
Build();
return _container.Resolve<T>();
}
}
var webContext = DependencyResolver.Current.GetRequestLifetimeScope()
.Resolve<IWebContext>();