I am trying to implement auto closing custom helper.
I have found how to to this below:
Custom html helpers: Create helper with "using" statement support
I have done everything except:
what i am supossed to return here?
public static Action BeginField(this HtmlHelper htmlHelper, string formName)
{
string result = string.Format("<div class=\"FullWidthForm\"><span>{0}</span>", formName);
result += "<ul class=\"Left\">";
htmlHelper.ViewContext.HttpContext.Response.Write(result);
return ???????
}
I am asking because i have error as follows:
Error 9 'FieldContainer.BeginField(System.Web.Mvc.HtmlHelper,
string)': not all code paths return a
value
so i do not have idea what to return
Ok I have created everything how ever:
public static class DisposableExtensions
{
public static IDisposable DisposableField(this HtmlHelper htmlHelper, string formName)
{
//'HtmlHelpers.DisposableHelper' does not contain a constructor that takes 2 arguments
return new DisposableHelper(
() => htmlHelper.BeginField(formName),
() => htmlHelper.EndField());
}
public static void BeginField(this HtmlHelper htmlHelper, string formName)
{
htmlHelper.ViewContext.HttpContext.Response.Write("<ul><li>" + formName + "</li>");
}
public static void EndField(this HtmlHelper htmlHelper)
{
htmlHelper.ViewContext.HttpContext.Response.Write("</ul>");
}
}
class DisposableHelper : IDisposable
{
private Action end;
// When the object is create, write "begin" function
// make this public so it can be accessible
public DisposableHelper(Action begin, Action end)
{
this.end = end;
begin();
}
// When the object is disposed (end of using block), write "end" function
public void Dispose()
{
end();
}
}
Your BeginField does not need to return Action.
Action is a delegate, a callback you need to pass to the DisposableHelper constructor. You will setup it as () -> htmlHelper.BeginField(formName). DisposableHelper works by remembering the two callbacks you pass in - first to start the tag (BeginField) which is called immediately, second to end the tag (EndField) which is called on disposal of the DisposableHelper.
UPDATE: This is how you should implement it.
a) Copy the DisposableHelper class.
b) Write an extension to DisposableExtensions:
public static class DisposableExtensions
{
public static IDisposable DisposableField(this HtmlHelper htmlHelper, string formName)
{
return new DisposableHelper(
() => htmlHelper.BeginField(formName),
() => htmlHelper.EndField()
);
}
}
c) Change your BeginField declaration to return void:
public static void BeginField(...)
d) Add EndField method to close the tag.
e) Use it this way:
using (Html.DisposableField("MyForm"))
{
...
}
Related
I've made my own Ajax "generic" (cant remember how you call this principle in C#) like this (only relevant functions):
public class Ajax<T>
{
public delegate void CallbackAjaxFinished(T j);
public void Get(string Url, CallbackAjaxFinished cbAjaxFinished)
{
/* blablah launch the Ajax call which calls back GetFinished() below */
}
private void GetFinished(HTTPRequest request, HTTPResponse response)
{
ConvertThenCallback(response, true);
}
private void ConvertThenCallback(HTTPResponse response, bool isGet)
{
try {
/* make conversion, T could be for example class JsonData */
j = (T)JsonUtility.FromJson<T>(response.DataAsText);
} catch (ArgumentException) { /* Conversion problem */
return;
}
}
}
That was working well, like this:
Ajax<JsonState> a = new Ajax<JsonState>();
a.Get(
baseURL + _urlGetState, /* get Url */
/* callback Ajax finished: */
(JsonState j) => { /* do stuff in the callback */ }
);
The problem is that Unity's JsonUtility doesnt handle nested arrays (...).
To make a long story short, I'd like in my "generic" stuff, to pass a custom "json decode" function callback, default=null, and in the ConvertThenCallback() function, do this:
if there's no custom function, call j = (T)JsonUtility.FromJson<T>(response.DataAsText); (like it already is now)
if there's a custom function, call something like j = (T)callback(response.DataAsText);
How would you do that in C#?
Update
Here's my JsonState + dependencies declaration:
[System.Serializable]
public class JsonGameDataCell
{
public JsonGameDataBoatCurrentPlayerShot[] c;
public JsonGameDataBoatOpponentShot[] o;
}
[System.Serializable]
public class JsonGameData
{
public JsonGameDataStart start;
public JsonGameDataCell[][] board;
}
[System.Serializable]
public class JsonData
{
public string player;
public JsonGameData game;
}
[System.Serializable]
public class JsonState
{
public int state;
public int state_sub;
public string message;
public JsonData data;
}
And my actual problem is that Unity Json utility can't decode nested arrays, so the property JsonGameDataCell[][] board is always set to null when I call JsonUtility.FromJson(). So I have to implement my own Json decoder. I'll use SimpleJSON which works very well, but I just want to use thise decoder only in that specific case.
Seems to me that you're seeking something called an interface. You can use them to mark some objects so that the application "knows" how to treat them.
You can create such interface as such :
public interface ICustomJson
{
void FromJson(string jsonString);
}
Now in your ConvertAndCallbackyou can just check if(typeof(T).GetInterfaces().Any(i => i == typeof(ICustomJson)))
If it does you can just create an instance of that class casted to ICustomJson and call FromJson(string) method.
Remember that your object can have no default ( parameterless ) constructor so you can create an uninitialized version of that class.
example ConvertAndCallback:
T result = null;
if(typeof(T).GetInterfaces().Any(i => i == typeof(ICustomJson)))
{
result = (T)FormatterServices.GetUninitializedObject(typeof(T));
((ICustomJson)result).FromJson(string);
}
else
{
result = (T)JsonUtility.FromJson<T>(response.DataAsText);
}
Another solution would be ( again ) to use an interface but only for deserializer part. This will involve another class ( or a factory ) to produce a deserializer for the specified type.
You can create an interface called IJsonSerializer with two methods inside T Deserialize(string) and string Serialize(T):
public interface IJsonSerializer<T>
{
T Deserialize(string jsonString);
string Serialize(T jsonObject);
}
Now having this interface, create a class which will implement this
public class JsonStateSerializer : IJsonSerializer<JsonState>
{
public JsonState Deserialize(string jsonString)
{
// put your deserialization code up in here
}
public string Serialize(JsonState jsonObject)
{
// put your serialization code up in here
}
}
Now create the default one:
public class DefaultJsonSerializer<T> : IJsonSerializer<T>
{
public T Deserialize(string jsonString)
{
return (T)JsonUtility.FromJson<T>(jsonString);
}
public string Serialize(T jsonObject)
{
return JsonUtility.ToJson(jsonObject);
}
}
Having these two would be easier to distinguish which one to use later in your ConvertAndCallback method.
Now if you want you can create some Attributes to mark which serializer will be applied to which object or use some factory for that.
I will go with the easiest method and just modify ConvertAndCallback method so that it will have another ( optional ) parameter.
void ConvertThenCallback(HTTPResponse response, bool isGet, IJsonSerializer<T> serializer = null)
{
try
{
if(serializer == null)
{
serializer = new DefaultJsonSerializer<T>();
}
j = serializer.Deserialize(response.DataAsText);
}
catch (ArgumentException)
{
/* Conversion problem */
return;
}
}
And apply this to your Get method too ( so that the serializer would be passed from public to private methods ):
public void Get(string Url, CallbackAjaxFinished cbAjaxFinished, IJsonSerializer<T> serializer = null)
{
// whenever you call ConvertAndCallback
ConvertAndCallback(param1, param2, serializer); // just pass the same serializer here
}
You can now use it with any kind of serializer that implements IJsonSerializer<T> interface or with the default one if none specified.
example usage:
Ajax<JsonState> a = new Ajax<JsonState>();
a.Get(
baseURL + _urlGetState, /* get Url */
/* callback Ajax finished: */
(JsonState j) => { /* do stuff in the callback */ },
new JsonStateSerializer()
);
// or if you want to use default one
Ajax<JsonState> a = new Ajax<JsonState>();
a.Get(
baseURL + _urlGetState, /* get Url */
/* callback Ajax finished: */
(JsonState j) => { /* do stuff in the callback */ }
);
I don't quite understand what you meant but will answer the part I do. Please clarify in the comment if that's what you wanted or if there's something unclear in my answer.
I have an IDisposable HTML helper to create a specific html structure that I need very often in my app. I use it with razor and its works perfectly
#using (Html.SlidePanel("settings-button"))
{
<span>panel content</span>
}
I have a html helper component based on the structure and I want to use my SlidePanel inside.
public class MyComponent : IHtmlString
{
private readonly HtmlHelper html;
public MyComponent(HtmlHelper html)
{
this.html = html;
}
public override string ToString()
{
return Render();
}
public string ToHtmlString()
{
return ToString();
}
private string Render()
{
// I want to use my SlidePanel at this place
string renderHtml = "<div>component html</div>";
return renderHtml;
}
}
public static class MyComponentHtmlHelper
{
public static MyComponent MyComponent(this HtmlHelper html)
{
return new MyComponent(html);
}
}
How can I achieve this ?
Thanks
You'll need to intercept the string that SlidePanel would normally be sending to the general output. Something like this should work:
var originalWriter = html.ViewContext.Writer;
using (var stringWriter = new StringWriter())
{
html.ViewContext.Writer = stringWriter;
using (html.SlidePanel())
{
stringWriter.Write("<div>component html</div>");
}
html.ViewContext.Writer = originalWriter;
return stringWriter.ToString();
}
So here you go, example HERE
public static class DisposableExtensions
{
public static IDisposable DisposableDiv(this HtmlHelper htmlHelper)
{
return new DisposableHelper(
() => htmlHelper.BeginDiv(),
() => htmlHelper.EndDiv());
}
public static void BeginDiv(this HtmlHelper htmlHelper)
{
htmlHelper.ViewContext.Writer.Write("<div>");
}
public static void EndDiv(this HtmlHelper htmlHelper)
{
htmlHelper.ViewContext.Writer.Write("</div>");
}
}
}
As you can see in example "Hello Stranger" placed in additional div
I find a solution thanks to Baximilian and StriplingWarrior answers
Yes, I need to intercept the string that SlidePanel would normally be sending to the general output. So I can't use the ViewContext.Writer.
And yes, I need to send methods a parameters to my SlidePanel constructor.
So the solution is to add a second constructor to SlidePanel class :
public string HtmlString;
public SlidePanel(Func<string> begin, Func<string> content, Func<string> end)
{
this.HtmlString = string.Format("{0}{1}{2}", begin(), content(), end());
}
And add public helpers inside the SlidePanel Component class
public static string BeginSlidePanel(this HtmlHelper html)
{
return BeginHtml();
}
public static string ContentSlidePanel(this HtmlHelper html, string htmlString)
{
return htmlString;
}
public static string EndSlidePanel(this HtmlHelper html)
{
return EndHtml();
}
And then, I can use my SlidePanel like this :
new SlidePanel(
() => html.BeginSlidePanel(),
() => html.ContentSlidePanel(GetMyHtmlContent()),
() => html.EndSlidePanel()).HtmlString
Thanks a lot !
I want to create Html helper that will display inner content only if user in role,
Something like this:
#using(Html.AdminBlock()) {
}
And the code in the block will shown only if user in role...
How I can done it?
If you didn't understand what I mean here example, I want that those 2 codes will return equal result:
#if(Html.IsUserInRole("Admin")) {
<span>hey</span>
}
.
#using(Htm.RoleBlock()) {
<span>hey</span>
}
What you are trying to do is not possible with an HTML helper that is returning IDisposable. The reason for that is because its body will always be rendered. You cannot conditionally exclude the body from being rendered in such a statement:
#using(Htm.RoleBlock()) {
<span>hey</span>
}
Besides, the following looks readable enough:
#if(Html.IsUserInRole("Admin")) {
<span>hey</span>
}
or you could write a helper that will return a boolean value and could be used like that:
#if(Html.IsAdmin()) {
<span>hey</span>
}
Update 2
So you want to keep as much logic out of the view as possible, in this case you can just pull the if conditions out of the view and into a HtmlHelper extension method.
public static class HtmlHelperExtensions
{
public static bool IsAdmin(this HtmlHelper htmlHelper)
{
return htmlHelper.ViewContext.HttpContext.Current.User.IsInRole("admin");
}
}
Usage:
#if (Html.IsAdmin()) {
...
}
Update
If what you want to only output something if a user is in a role this sort of helper is completely overkill. You should go for a simple if statement in your view.
#if (HttpContext.Current.User.IsInRole("admin")) {
...
}
Making a custom helper
I posted a blog post about this very topic last year where I opened up the ASP.NET MVC source to see how BeginForm() was put together and made my own. Here are the highlights, this will allow you to wrap a <div> around a block in an MVC view.
public class MvcDiv : IDisposable
{
private bool _disposed;
private readonly FormContext _originalFormContext;
private readonly ViewContext _viewContext;
private readonly TextWriter _writer;
public MvcDiv(ViewContext viewContext)
{
if (viewContext == null)
{
throw new ArgumentNullException("viewContext");
}
_viewContext = viewContext;
_writer = viewContext.Writer;
_originalFormContext = viewContext.FormContext;
viewContext.FormContext = new FormContext();
Begin();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Begin()
{
_writer.Write("<div>");
}
private void End()
{
_writer.Write("</div>");
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
End();
if (_viewContext != null)
{
_viewContext.OutputClientValidation();
_viewContext.FormContext = _originalFormContext;
}
}
}
public void EndForm()
{
Dispose(true);
}
}
Then put this extension method somewhere:
public static class HtmlHelperExtensions
{
public static MvcDiv BeginDiv(this HtmlHelper htmlHelper)
{
return new MvcDiv(htmlHelper.ViewContext);
}
}
Then you can use it like so:
#using (Html.BeginDiv())
{
...
}
Let me try to simplify my question:
I have four classes: Admins, Users, Players, Roles
The database returns names of methods that I will need to execute. For example if Admins_GetName is returned then GetName() method will need to be executed on the Admins class.
If Players_GetRank is returned then GetRank() method will need to be called on the Players class.
I don't want to write a huge IF or SWITCH statement with all my business logic in it. What would be the most efficient solution WITHOUT using reflection ? If possibly I would like to avoid the performance hit that reflection brings.
Keep in mind that all methods may have different parameters and but will return strings.
Here is what I'm thinking to do now:
1) Have a method with a switch statement that will break apart the database value and find the class and method I need to execute.
Something like:
switch(DbValue)
{
case DbValue == "Admins_GetName":
Declare a delegate to Admins.GetName();
return;
case: DbValue = "Players_GetRank"
Declare a delegate to Players.GetRank();
return;
.
.
.
etc
}
return class/method reference;
2) Pass the declaration from above to:
var myValue = Retrieved method.invoke()
Can you guys suggest me with the best way to accomplish this or help me out with the correct syntax on my idea of how to implement it.
Thank you.
Needs a little more context; for example, do all the methods in question have the same signature? In the general case, reflection is the most appropriate tool for this, and as long as you aren't calling it in a tight loop, it will be fine.
Otherwise, the switch statement approach is reasonable, but has the maintenance overhead. If that is problematic, I would be tempted to build a delegate cache at runtime, for example:
using System;
using System.Collections.Generic;
public class Program
{
public string Bar { get; set; }
static void Main()
{
var foo = new Foo();
FooUtils.Execute(foo, "B");
FooUtils.Execute(foo, "D");
}
}
static class FooUtils
{
public static void Execute(Foo foo, string methodName)
{
methodCache[methodName](foo);
}
static readonly Dictionary<string, Action<Foo>> methodCache;
static FooUtils()
{
methodCache = new Dictionary<string, Action<Foo>>();
foreach (var method in typeof(Foo).GetMethods())
{
if (!method.IsStatic && method.ReturnType == typeof(void)
&& method.GetParameters().Length == 0)
{
methodCache.Add(method.Name, (Action<Foo>)
Delegate.CreateDelegate(typeof(Action<Foo>), method));
}
}
}
}
public class Foo
{
public void A() { Console.WriteLine("A"); }
public void B() { Console.WriteLine("B"); }
public void C() { Console.WriteLine("C"); }
public void D() { Console.WriteLine("D"); }
public string Ignored(int a) { return ""; }
}
That approach can be extended to multiple target types by using generics:
static class FooUtils
{
public static void Execute<T>(T target, string methodName)
{
MethodCache<T>.Execute(target, methodName);
}
static class MethodCache<T>
{
public static void Execute(T target, string methodName)
{
methodCache[methodName](target);
}
static readonly Dictionary<string, Action<T>> methodCache;
static MethodCache()
{
methodCache = new Dictionary<string, Action<T>>();
foreach (var method in typeof(T).GetMethods())
{
if (!method.IsStatic && method.ReturnType == typeof(void)
&& method.GetParameters().Length == 0)
{
methodCache.Add(method.Name, (Action<T>)
Delegate.CreateDelegate(typeof(Action<T>), method));
}
}
}
}
}
I need to get MethodInfo for method called in Action delegate in order to check, whether methods called in Action has MyCustomAttibute
public void Foo( Action action )
{
if(Attribute.GetCustomAttributes(action.Method, typeof(MyCustomAttribute)).Count() == 0)
{
throw new ArgumentException("Invalid action");
}
}
The Foo method should be able to be called as following:
Foo(() =>
{
instanceOfFooClass.Method1().Method2();
});
In Foo method I want to be sure that Method1 and Method2 has MyCustomAttribute. However action.Method is giving me the MethodInfo, which is the action of delegate, which happens when using lambda expression. Is there any way to get Method1 and Method2 MethodInfo?
As mentioned in the comments, Expression<T> is probably the best way to achieve this. However, it requires a Compile() at runtime so it should be performance profiled.
With Expression<T> you can easily get access to Method info like this:
public MethodInfo GetMethodInfo(Expression<Action> action)
{
return ((MethodCallExpression)action.Body).Method;
}
But, before executing the action you must do this:
private void InvokeMethod(Expression<Action> action)
{
action.Compile().Invoke();
}
EDIT
Ah yes, I forgot how to get access to the customer attribute. You would do it like this:
var methodInfo = ((MethodCallExpression)myAction.Body).Method;
var attributes = methodInfo.GetCustomAttributes<T>(true);
EXAMPLE
Here is an example showing passing chained method calls to Expression<Action>:
public class ActionTest
{
public void DoAction(Action action)
{
action();
}
public void DoExpressionAction(Expression<Action> action)
{
var method2Info = ((MethodCallExpression)action.Body).Method;
// a little recursion needed here
var method1Info = ((MethodCallExpression)((MethodCallExpression)action.Body).Object).Method;
var myattributes2 = method2Info.GetCustomAttributes(typeof(MyAttribute), true);
var myattributes1 = method1Info.GetCustomAttributes(typeof(MyAttribute), true);
action.Compile().Invoke();
}
}
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
private string message;
public MyAttribute(string message)
{
this.message = message;
}
}
public class MethodTest
{
[MyAttribute("Number1")]
public MethodTest Method1()
{
Console.WriteLine("Action");
return this;
}
[MyAttribute("Number2")]
public MethodTest Method2()
{
Console.WriteLine("ExpressionAction");
return this;
}
}
class Program
{
static void Main(string[] args)
{
ActionTest target = new ActionTest();
MethodTest instance = new MethodTest();
target.DoExpressionAction(() => instance.Method1().Method2() );
Console.ReadLine();
}
static void Method1()
{
Console.WriteLine("Action");
}
static void Method2()
{
Console.WriteLine("ExpressionAction");
}
}
If you call your Foo() methdod like this:
Foo(instanceOfFooClass.Method);
Your code works as you'd expect (void methods are actions, after all).
On a side note, I think "chaining" method calls in fact counts as you're only passing the last one through.
Full sample demonstrating the behavior:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication4
{
class MyCustomAttribute : Attribute { }
class FooClass
{
[MyCustom]
public void DecoratedMethod() { Console.WriteLine("Decorated Method - executed."); }
public void NotDecoratedMethod() { Console.WriteLine("Not Decoreated Method - executed."); }
}
class Program
{
static void Main(string[] args)
{
FooClass instanceOfFooClass = new FooClass();
Foo(instanceOfFooClass.DecoratedMethod);
Foo(instanceOfFooClass.NotDecoratedMethod);
Console.ReadLine();
}
public static void Foo(Action action)
{
if (Attribute.GetCustomAttributes(action.Method, typeof(MyCustomAttribute)).Count() == 0)
Console.WriteLine(string.Format("Invalid method {0}", action.Method.Name));
else
{
Console.WriteLine(string.Format("Valid method {0}", action.Method.Name));
action.Invoke();
}
}
}
}