Write additional HTML comments in razor - c#

I'm struggling with the following problem and I can't find an acceptable way to solve it.
My challenge: write out HTML comments just before the actual property value in a Razor view.
This is my (simplyfied) Viewmodel:
public class Article
{
public string Title {get;set;}
}
To write out this title I simply do this in my Razor view:
<h2>#Model.Title</h2>
Now I want to write out a html comment just before the actual title so the generated HTML looks like this (simplyfied):
<h2><!-- some parameters for a 3th party system --> This is my title</h2>
The HTML comment comes from an Attribute I applied to the 'Title' attribute. It's value is generated, so the attribute-value is added at runtime using the TypeDescriptor from the .NET framework.
Now I know I could achieve this by simply writing out all my properties using an HTML helper. Like this: #MyHelper.Write(m => m.Title)
But since potentially ALL my properties need this HTML comment I want to avoid the use of an HTML helper since it clutters the View and doesn't make the view look nice and (more) readable.
This is what I have tried:
Created a custom Razor base page (Inheriting from WebViewPage<TModel>). And overwriting it's 'Write' method.
This kind of works but the BIGGEST problem here is that I don't know which property is been written out at that moment. There is no way of getting the current property name in the 'Write' method. So now I dynamically search my Model to find a property with the value that's been written out and prepend the HTML comment from the attribute.
My question: is there another approach to accomplish what I want. As sais before: I want to avoid using an HTML helper to write out all my properties. (Think about loops, etc. It's just not nice).
Also, adding this HTML comment in my Controller is no option since:
it's not part of the actual value. Is a sort of metadata.
The HTML comment should be added to int's, double's and DateTime's. There is no way to adjust a double property to include a string. (Image a List<DateTime>. All date's need this HTML comment)
the HTML comment should be added based on a web.config setting. Yes or No. (The actual HTML comment is different for each value of a property)
I realize this question is rather long. Sorry for that. Any thoughts are appreciated.

You can use the existing #Html.Raw(Model.Title)
Alternatively you can use a display templates. Add a UIHintAttribute to the properties you wish to behave this way.
public class MyModel
{
[UIHint("Raw")]
public string MyString { get; set; }
}
Create a new display template called Raw.cshtml that accepts model of type string:
#model string
#Html.Raw(model)
Then in your view you can use:
#Html.DisplayFor(m => m.MyString)
This still requires that you use a helper (DisplayFor). This is a recommended practice that allows you to easily change the behavior of one or many fields with minimal code changes.

Related

using knockout to pass an HTML string to a C# controller. What am I doing wrong?

Alright. I can get the HTML I need from the page (it's all in a DIV). That's not the problem. What I need to do is take the HTML and pass it, via a C# class into a controller.
I tried doing something like this with knockout/jQuery:
var Details = $("#Details").html();
console.log(Details);
DetailsPdf.DetailsMarkup = JSON.stringify(Details);
var jsonData = ko.toJS(Details);
ko.utils.postJson("/MyController/MyAction", DetailsPdf);
The knockout actually DOES get me the relevant HTML. But when I pass it to my class, I get an exception that reads:
A potentially dangerous Request.Form value was detected from the client.
Then it partially shows the HTML I was sending as a part of the exception. I can't even seem to pass in the entities themselves without getting that exception.
This is an app with certain company-mandated security features, so turning off validation is not an option.
I need the HTML, or at least a way to re-create it on the server in the C#.
I'm still fairly new to knockout. Does anyone have any suggestions here?
You should have mentioned that:
This is an app with certain company-mandated security features, so
turning off validation is not an option.
In your recent question Using iTextSharp with the knockout JavaScript framework?. I could have provided this answer there.
I'm not sure why decorating the controllers Action with [ValidateInput(false)] isn't working, but that answer's fully working source code is available. Whatever the reason, you should only need a few changes to workaround the issue:
(1) Base64 encode the HTML in your JavaScript:
ko.utils.postJson("/MyController/MyAction", window.btoa(DetailsPdf));
(2) Decode string in your MVC Controller:
[HttpPost]
public ActionResult Index(string xHtml)
{
xHtml = Encoding.UTF8.GetString(Convert.FromBase64String(xHtml));
(3) Deserialize that string to your model / entities with Json.Net or other.
Above steps have also been tested and verified working. ;)
You should be able to decorate your model (the one that the controller action is expecting) with the [AllowHtml] attribute on the property that has the HTML.
When you do that, MVC skips the validation for that property.
Here's a link to the documentation for more information.
Note Use this ONLY when you need to. It does open a vector for XSS if misused.
Edit: If for some reason, You can't use the [AllowHtml] attribute, you can turn off validating the request for that one action with [ValidateInput(false)].
Same rules apply. Use that very sparingly. This means none of security validations will run against that particular model in that particular action only.

MVC dynamically "expanding" #Html.EditorFor()

Suppose I have a model with some string property.
Imagine also that this string property is actually a comma delimited list of values.
If I want to make a form to update values on my model it would be easy enough to call:
#Html.TextBoxFor(model => model.myCommaDelimitedProp, new { #class = "form-control", placeholder = "CommaDelimitedPropValue" })
However, that is not good enough for the intended application.
I would like to have a custom EditorFor() that could somehow take my property, use string parsing and next generate an array of text boxes to display the pre-existing values.
That would also be relatively trivial.
However, what I cannot seem to solve, mainly because I lack client side experience (js, jquery, angular, ...):
How could I make my editor such that there would be a small button so that I could dynamically add rows, fill them such that, upon form submission, I could string the new values onto the pre-existing string.
So specifically, what would any of you use to achieve this client side behaviour?
I just need some help to be put on the way...
You can achieve this with editor templates. There's a quick intro I threw together on my blog. The only additional thing you'll need is UIHint. Since you won't be able to rely on a specific C# type or DataType annotation to determine that this should be treated as a comma-delimited property. You can just explicitly tell Razor what template it should use. For example:
[UIHint("CommaDelimited")]
public string MyCommaDelimitedProperty { get; set; }
Which would correspond to the editor template: Views\Shared\EditorTemplates\CommaDelimited.cshtml. Once you set up that view how you like it. Then in your form you just call:
#Html.EditorFor(m => m.MyCommaDelimitedProperty)
EDIT
I'll leave my previous answer because it could still be helpful in terms of being able to generate a control for a specific type of thing. You actually may still need to use it to get the right set up on your field to make the JS work properly.
However, when it comes to the client-side handling of this, I figured there had to be something out there already to solve this problem. (Never do more work than you have to.) A cursory search turned up a little script called Tokenfield for Bootstrap. I'm not sure if you're using Bootstrap or not. If not, I also found jQuery Tokeninput and jquery.token-field. I'm sure there's others, as well.

How to include #Html.Actionlink in C# text string?

While the #Html.Actionlink() helper is very convenient for building <a> elements in the .cshtml files, is it possible to construct them inside C# strings, such that they are subsequently rendered correctly in the HTML output?
For example, if I assign a string variable a value similar to the following:
Book.ReadMore = "Click #Html.ActionLink(\"this link\", \"About\", \"Home\") to read more.";
And then I try to display it (the literal text plus the link) through my .cshtml page, using code similar to:
<p>#Model.ReadMore</p>
All I get in the browser is the whole string exactly as I typed it, including the #Html... etc:
Click #Html.ActionLink("this link", "About", "Home") to read more.
Now, for proper SoC, I know that it's not the best of practices to have HTML stuff included in C# code, but is it at all possible to get the proper <a> link in this scenario, instead of the string itself?
EDIT: More information - This string is just one item in a collection of about 20-30 strings (displayed using a for loop in the View). Only a small handful of those items need a link (which is different in each case). Since, as mentioned above, I agree that it's obviously not good practice to use Razor/HTML in Model code, I'm trying to get a simple approach (if possible) which would give me the flexibility of building the link somewhere at the right place, while still yielding the maintainability of MVC SoC.
There must be a "right" way of doing this, which is simple yet maintainable.
Your model should not contain HTML, that's a view concern and belongs in view code. Probably you should be using a Razor helper.
In your App_Code folder (create one if you don't have one), add a file, ReadMoreHelpers.cshtml:
#helper ReadMore() {
<text>Click #Html.ActionLink("this link", "About", "Home") to read more.</text>
}
Then in any view:
#ReadMoreHelpers.ReadMore()
And that will output what you want. If you insist on putting that property in your view, you could do:
Book.ReadMore = "Click " + #Html.ActionLink("this link", "About", "Home").ToHtmlString() + " to read more.";
Then in your view, make sure you use Raw:
#Html.Raw(Book.ReadMore)
However, I couldn't recommend more strongly that you do not put HTML in your model properties.
I don't think so. The Razor view engine will interpret the ActionLink code during run-time while stuffing it as part of a C# string will be interpreted during compile time.

MVC Strongly typed IQueryable<IGrouping<TKey, TElement>> model

I'm trying to create a strongly typed model for one of my Views in MVC. The model is the result of a LINQ GroupBy query so it is the type shown below (grouping employees by first letter of surname).
#model IQueryable<IGrouping<string, Employee>>
I'm unsure why but it doesn't let me have a model of this type. The error message I get is:
An opening "<" is missing the corresponding closing ">". Which is incorrect.
I know I can create a view specific model and populate that instead but I'd like to know why this model doesn't seem to work?
By default, a very limited set of namespaces are available for direct use in razor views. Try to expand it to fully qualified names and see if the problem persists:
#model System.Linq.IQueryable<System.Linq.IGrouping<string, Name.Space.Employee>>
I don't know why you'd be getting this error, since you appear to be using correct Razor code. It's possible that there's actually a bug elsewhere in the page that is being made manifest through this incorrect error message.
A workaround, which may help you determine the real source of the bug, would be to create your own strongly-typed model class, which could have this data as its property:
public class EmployeeListViewModel
{
public IQueryable<IGrouping<string, Employee>> EmployeesByCompanyTitle {get;set;}
}
(There are those who would argue that this is a better approach anyway, since you can now add information to your view model more easily.)

View model properties has changing validation rules at run time

I'm new to C# MVC and I'm trying to add some dynamic validation checks to my view models that are used in a form. For example, I have a string property called FirstName. I can add the attribute StringLength(10) and Required() to it.
My problem is, depending on some other field, the FirstName StringLength could vary from 10 to 20, etc. I still want to use the MVC validations but be able to modify it. I know that attributes are bound to the class so maybe I'm using the wrong thing.
I want the abilities for attribute validation but have it modifiable at run time. Is this possible?
The values in an attribute have to be literals. You can still use attribute based validation, but you will need to use the CustomValidation tag and point it at a method to use. If it depends on multiple fields in the object, you will want to put this on the class rather than the property.
It seems you can add validation attributes at runtime by implementing DataAnnotationsModelValidatorProvider:
Dynamic Attributes # forums.asp.net

Categories

Resources