I'm making and setting AntiXssEncoder for my web project which uses mvc3 and .net4, and I've done these steps:
add AxtiXSSLibrary reference
create AntiXSSEncoder derived from HttpEncoder
override the HtmlEncode method: output.Write(Encoder.HtmlEncode(value));
set encoderType in web.config to <httpRuntime encoderType="AntiXSSEncoder, MyDll"/>
But I still can see the alert popup by xss input (XssTest<script>alert("test");</script>).
So I tested and found out the default encoder doesn't encode values which are assigned to ViewBag. My test code is below and it shows one isn't encoded.
//In controller code
[ValidateInput(false)]
public ActionResult AntiXss(string TextArea)
{
ViewBag.DisplayInput = TextArea;
ViewBag.DisplayEncodedInput = Encoder.HtmlEncode(TextArea);
return View();
}
//In view code
#using (Html.BeginForm("AntiXss", "Test"))
{
#Html.TextArea("TextArea")
<p/>
#Html.Raw(ViewBag.DisplayInput)
<p/>
#Html.Raw(ViewBag.DisplayEncodedInput)
//#ViewBag.DisplayInput
<p/>
<input type="submit" value="ok"/>
}
//In redered page code
<textarea id="TextArea" name="TextArea">
XssTest<script>alert("Test");</script></textarea> <p/>
XssTest<script>alert("Test");</script> <p/>
XssTest<script>alert("Test");</script> <p/>
Can any one give me an answer or clue?
Related
I have a View MyView.cshtml with the following content:
#using MyProject.ViewModels
#model MyProject.ViewModels.MyViewViewModel
<form asp-action="Test" method="Post">
<component type="typeof(MyProject.Views.Home.Test)" render-mode="ServerPrerendered" />
<input type="submit" value="send"/>
</form>
And I have the Razor Component Test.razor with the following content (with Blazor Syntax):
#page "/Test"
<div class="form-group top-buffer #Visible">
<div class="row">
<div class="col-2">
<label asp-for="TestName" class="control-label"></label>
</div>
<div class="col-3">
<input asp-for="TestName" class="form-control" />
<span asp-validation-for="TestName" class="text-danger"></span>
</div>
</div>
</div>
<button #onclick="Show">Show</button>
#code {
public string Visible { get; set; } = "hidden";
protected async Task Show()
{
Visible = "";
}
}
The Class MyViewViewModel would look like this:
namespace MyProject.ViewModels
{
public class MyViewViewModel
{
[Display(Name = "Test Name:")]
public string TestName { get; set; }
}
}
Works all pretty fine so far. However I now want to use this component as part of a Web form which will be sent to the controller after submission. That's why I need to access and change properties of my ViewModel 'MyViewViewModel'. Unfortunately I did not find any answer in the internet on how to do that. I can't use #model MyProject.ViewModels.MyViewViewModel like in the view because this will give me a compilation error. I wonder if I need to use #inject, but if yes, I don't know how...
(parts are used from this example: https://jonhilton.net/use-blazor-in-existing-app/)
When you mix Blazor in a Razor Page, you can do the following:
Render a Razor Component
Interact with a Razor Component
Pass a Razor Component values
Please keep in mind that you are dealing with two different life-cycles. So if you do work inside of a Razor Component, the component will update but not effect the Razor Page it is hosted inside of. So mixing Razor Components and Pages with forms would be difficult.
More specifically to the OP. To pass data from your ViewModel to the component you may use the following method.
#using MyProject.ViewModels
#model MyProject.ViewModels.MyViewViewModel
<form asp-action="Test" method="Post">
<component type="typeof(MyProject.Views.Home.Test)"
render-mode="ServerPrerendered"
param-Name="#Model.TestName"/>
<input type="submit" value="send"/>
</form>
Test.razor
<h3>HelloWorld</h3>
Hello #Name
#code {
[Parameter]
public string Name { get; set; } = "undefined";
}
About life cycles
Basically when you have a button in Blazor, it will trigger an event which causes the component to re-render. You could imagine it like an iframe, or update-panel. When you have a button in a Razor page, it does a HTTP call round trip and reloads the page entirely. There is no event system in place to tell Blazor to invoke an HTTP call round trip to refresh the Razor page's content and vise versa. You can only one-way data-bind from Razor pages to Blazor, think write-only, and only when the page loads.
To hopefully add to the info. With a ASP.Net Core MVC project host Blazor webassembly, I was trying to pass a viewmodel into a razor component using this code in my view cshtml file:
<component Type="typeof(Leave)" render-mode="WebAssembly" model="new { model = (MyViewModel)#Model})"/>
But it would fail to render the razor component if I tried to access data in the viewmodel from the razor component with an Object not set exception. I think it was accessing the data before the view model has been initialized. Maybe if I set a default value this could avoided?
I found by using this instead I was able to get it working.
#(await Html.RenderComponentAsync<Leave>(RenderMode.WebAssembly,new { model = (MyViewModel)#Model}))
Edit
Seems you also need to register the viewModel class in the services in the Blazor WASM project in the Program.cs file.
builder.Services.AddScoped(sp => new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped<MyViewModel,MyViewModel>(); // <= add this line
await builder.Build().RunAsync();`
Without that I would get an error saying the property could not be found.
Hopefully this saves someone else some time :-)
I've created a EditController to fetch and edit the contents of my database in asp.net core project. The Controller is given below:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(MyObject model)
{
if (ModelState.IsValid)
{
await _myObjectRepository.UpdateMsg(model);
return RedirectToAction("Index");
}
return View();
}
I've used the following script tag to reference the ckeditor and kept it on Edit.cshtml.
Inside the form tag I've put the following lines of code to display the editor and display the data from the database inside the editor.
<div class="form-group">
<label asp-for="Body" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<textarea asp-for="Body" id="editor1" name="editor1"></textarea>
</div>
</div>
<script type="text/javascript">CKEDITOR.replace('Body');</script>
I've no problem displaying the data from database to the editor. But as I try to change the text in the editor, no text would be present in the database.
So tested the code without using the editor i.e. I simply used tag instead of the CKEditor, with usual razor attributes and it worked fine. How can I solve this?
I believe you have a property in the MyObject class to store the content of the CKEditor. Lets suppose "ckEditorVar" is the property to store the ckeditor content. Following code works for me. I hope it will work for you too.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(MyObject model)
{
if (ModelState.IsValid)
{
await _myObjectRepository.UpdateMsg(new MyObject
{
ckeditorVar = Request.Form["editor1"].ToString(),
});
return RedirectToAction("Index");
}
return View();
}
i was looking for good trick to handle multiple submit button in form and then i got some advice from this url and i followed but fail.
How do you handle multiple submit buttons in ASP.NET MVC Framework?
posted by #Andrey Shchekin.
he just said create a class like below one so i did in same controller
public class HttpParamActionAttribute : ActionNameSelectorAttribute {
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
return false;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
then multiple submit button in the view look like & also controller code look like below
<% using (Html.BeginForm("Action", "Post")) { %>
<!— …form fields… -->
<input type="submit" name="saveDraft" value="Save Draft" />
<input type="submit" name="publish" value="Publish" />
<% } %>
and controller with two methods
public class PostController : Controller {
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveDraft(…) {
//…
}
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Publish(…) {
//…
}
}
but when i test his code it never work. so any can tell me where i am making the mistake or code itself is wrong for handling the situation. thanks
View:
<input type="submit" name="mySubmit" value="Save Draft" />
<input type="submit" name="mySubmit" value="Publish" />
Controller Action:
[HttpPost]
public ActionResult ActionName(ModelType model, string mySubmit)
{
if(mySubmit == "Save Draft")
{
//save draft code here
} else if(mySubmit == "Publish")
{
//publish code here
}
}
I had to deal with the similar scenario when I had the requirement that Users can finalize or save progress of the hospital infant record - essentially both actions are submit but one validates the record for insertion into the main DB table and another one saves it into a temp table without any validation. I handled it like this:
I have 2 buttons both are type submit with different IDs (btnSave and btnFinalize). When btnSave is clicked I intercept that event with some JQuery code:
$("#btnSave").click(function () {
$("#SaveForm").validate().settings.rules = null;
$('#SaveForm').attr('action', '#(Url.Content("~/Home/EditCase?finalize=false"))');
});
As you can see I modify the action attribute of the form to point to a different URL with a querystring attribute of finalize = false. I also remove any validation present on the model. If the other button is clicked I do nothing - executes the default behavior.
And in my controller I have a single action that handles both submit actions:
public ActionResult EditCase(EditInfantModel model, bool finalize = true)
{
// Logic for handling submit in here...
}
I think you can apply the similar technique for your problem. I'm not sure if it's the answer you're looking for but I thought it was worth mentioning...
There is a default submit button for the #FileUpload.GetHtml. But I am expecting to have a submit button inside the Html begin form and use that substitution to submit the list of files with some more parameters. But when I do that the passing IEnumerable is always null in the Action method.
This is my Action method:
[HttpPost]
public ActionResult Change(IEnumerable filesList, Guid ID, string Btn)
{....
#using (Html.BeginForm("Change", "Home",FormMethod.Post))
{
<textarea id="textArea" name="epost2" class="frm_txtfield_big" style="float:left; width:638px; height:200px;"></textarea>
<input type="hidden" name="supportID" value="#Model.ID" />
#FileUpload.GetHtml(name: "ChooseFile",initialNumberOfFiles: 1,allowMoreFilesToBeAdded: true,includeFormTag: false)
.......}
But this is not passing the list of files to the method.
Am doing it wrong or what is the wrong with the code.
I have not included the enctype = "multipart/form-data" inside the Html.BeginForm So that the value is not taken to the file input. Now it ok.
This will give you a good explanation.
I have a page in MVC3 with a model of "pageModel".
In this page I have:
#{ Html.RenderPartial("_subPage", Model.subModel); } (Pagemodel.submodel)
In my controller I am doing:
[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Results(pagemodel model, string frmAction)
{
}
The page loads fine the first time, but when I postback into the httpPost action, model.submodel is always null.
My question is, how do I return an updated model from the RenderPartial (if at all). I can get my model INTO the partial, but not back!
The problem with partials is that they do not preserve the navigational context. This means that any input fields that you might have put inside this partial will have incorrect names and the default model binder will not be able to retrieve the values back when you POST. Your HTML will look like this:
<input type="text" name="Prop1" value="property 1 value" />
<input type="text" name="Prop2" value="property 2 value" />
whereas the correct is:
<input type="text" name="subModel.Prop1" value="property 1 value" />
<input type="text" name="subModel.Prop2" value="property 2 value" />
In order to achieve this correct markup I would recommend you using editor templates.
So you replace:
#{ Html.RenderPartial("_subPage", Model.subModel); }
with:
#Html.EditorFor(x => x.subModel)
and then you move your _subPage.cshtml partial into ~/Views/Shared/EditorTemplates/SubModelType.cshtml where SubModelType is the type of the subModel property:
#model SubModelType
#Html.EditorFor(x => x.Prop1)
#Html.EditorFor(x => x.Prop2)
Now when you look at the generated HTML the corresponding input field names should be prefixed with subModel and inside the POST controller action the model.subModel property will this time be properly initialized and populated from the values that were entered by the user in the input fields.
you'll need to change your partialview to accept the top level model, i.e:
#{ Html.RenderPartial("_subPage", Model); }
which would then render your properties in the partialview with the correct property names i.e. :
<input type="text" name="subModel.MyProperty" value="somevalue" />
It would also mean that your returned model in the HttpPost action will have to correct navigational relationship intact.
this is just one of those caveats related to viewmodels and hierarchies. Oh, btw, in mvc3, you don't need the verbose [AcceptVerbs(HttpVerbs.Post)] for posts. You can simply use [HttpPost]
You can also perform the following.
#Html.RenderPartial(
"_subPage",
Model.subModel,
new ViewDataDictionary
{
TemplateInfo = new TemplateInfo
{
HtmlFieldPrefix = "subModel"
}
});
Your partial view will remain as is, using the #model SubModel