Form Validation Messages in ASP.NET MVC2 - using images instead of text for error messages - asp.net-mvc-2

OK - at the moment, to validate my pages I am using [Required] in my model in an MVC2 C# project.
For eg in my model I have:
[DisplayName("Username")]
[Required(ErrorMessage = "Please enter a Username")]
public string UserName { get; set; }
... and in my view I have
<%=Html.ValidationMessageFor(x => x.UserName, "*")%>
But then this isn't consistent with the rest of the styling and error trapping of the rest of our site which was written in Classic ASP.
I want to be able to recreate if possible the validation styles in the images below.
So on loading the page (not on submitting) we might see a display similar to this, with alt and title of the M icon displaying "Please enter a Username":
And then if we try and submit with missing values - we see
Again hovering over the red x will display the error message.
Is there a straightforward way of achieving this styling of validation and if so what is the best way to go about it...
Thank you for any helpful hints, tips, suggestions:

You should beable to achieve this by creating your own HtmlHelper extension method.
E.g.
public static string ValidationImage(this HtmlHelper htmlHelper, string modelName)
{
if (modelName == null)
{
throw new ArgumentNullException("modelName");
}
if (!htmlHelper.ViewData.ModelState.ContainsKey(modelName))
{
return null;
}
ModelState modelState = htmlHelper.ViewData.ModelState[modelName];
ModelErrorCollection modelErrors = (modelState == null) ? null : modelState.Errors;
ModelError modelError = ((modelErrors == null) || (modelErrors.Count == 0)) ? null : modelErrors[0];
if (modelError == null)
{
return null;
}
string messageText = GetUserErrorMessageOrDefault(htmlHelper.ViewContext.HttpContext, modelError, modelState);
TagBuilder builder = new TagBuilder("img");
builder.MergeAttribute("src", "urlToYourCrossImage");
builder.MergeAttribute("class", HtmlHelper.ValidationMessageCssClassName); //Or your own custom class for the img tag here
builder.MergeAttribute("alt", messageText);
builder.MergeAttribute("title", messageText);
return builder.ToString(TagRenderMode.SelfClosing);
}
Have a look at the ASP.NET MVC ValidationExtensions source code to get some ideas about how to write some overloads for it.
HTHs,
Charles

Related

Codefluent Potentially dangerous Request.Form value with richtext fields

After adding the multivalue (flags) enumeration solution (which works very well, thank you) from
http://blog.codefluententities.com/tag/multi-enumeration-values/
to our MVC project we are now getting the dreaded "Potentially dangerous Request.Form value" on richtext fields across the board that we're using to generate html with a wysiwyg editor (summernote in this case).
If I remove summernote and just submit plain text the fields work perfectly, however putting any html code into the text input generates the error.
Fortunately, the error is coming out of the code just added (above) for the multi-enumeration on line 246:
Exception Details: System.Web.HttpRequestValidationException: A potentially dangerous Request.Form value was detected from the client (Description="...rem ipsum <strong>dolor</stron...").
Source Error:
Line 244: continue;
Line 245:
Line 246: Add(name, nvc[name]);
Line 247:
Line 248: }
EDIT:
For clarity, here is the whole method in question:
private void AddRange(NameValueCollection nvc)
{
foreach (string name in nvc)
{
// handle MultiSelectList templates
const string listSelectedToken = ".list.item.Selected";
const string listValueToken = ".list.item.Value";
if (name.EndsWith(listSelectedToken))
{
List<bool> bools = CodeFluent.Runtime.Utilities.ConvertUtilities.SplitToList<bool>(nvc[name], ',');
string propertyName = name.Substring(0, name.Length - listSelectedToken.Length);
string valueKey = propertyName + listValueToken;
List<string> keys = CodeFluent.Runtime.Utilities.ConvertUtilities.SplitToList<string>(nvc[valueKey], ',');
int j = 0;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keys.Count; i++)
{
if (bools[j])
{
if (sb.Length > 0)
{
sb.Append(CodeFluentConfiguration.EntityKeyListSeparator);
}
sb.Append(keys[i]);
j++;
}
j++;
}
Add(propertyName, sb.ToString());
continue;
}
if (name.EndsWith(listValueToken))
continue;
Add(name, nvc[name]);
}
}
Have I missed something in the multi-value implementation?
Thanks,
Russ
I don't think this error is related to the use of a multi-valued enumeration. In fact you post a value for the Description field that contains HTML tags (strong). By default ASP.NET prevents this and throw a validation exception.
If you expect your users to enter HTML, you must instruct ASP.NET to authorize HTML.
Change the EntityValueProvider
AddRange(context.HttpContext.Request.Unvalidated.Form); // Add Unvalidated
AddRange(context.HttpContext.Request.Unvalidated.QueryString);
Or use the web.config: validateRequest or requestValidationMode
<system.web>
<pages validateRequest="false" />
<httpRuntime requestValidationMode="2.0" />
</system.web>
Use AllowHtmlAttribute
public class Sample
{
[AllowHtml]
public string Description {get;set;}
}
Or ValidateInputAttribute
[HttpPost, ValidateInput(true, Exclude = "Description")]
public ActionResult Edit(int id, FormCollection collection)
{
...
}

Send Email fields not rendering in Sitecore Web Forms For Marketers

I have an issue with the WFFM Send Email Message save action (Sitecore 6.5.0). I'm trying to send an email that includes the form placeholders from the "Insert Field" dropdown in the Send Email editor. Sometimes the fields will render correctly, but most times the email will include the placeholder text instead of the field's actual value.
For example, this is the email that is coming through:
First Name: [First Name]
Last Name: [Last Name]
Email: [Email Address]
Company Name: [Company Name]
Phone Number: [Phone Number]
I think it has to do with the Send Email editor using a rich text editor for the email template, but I've tried adjusting the message's HTML to no avail. This is what the markup looks like: (the <p> tags and labels used to be inline, but that didn't work either)
<p>First Name:
[<label id="{F49F9E49-626F-44DC-8921-023EE6D7948E}">First Name</label>]
</p>
<p>Last Name:
[<label id="{9CE3D48C-59A0-432F-B6F1-3AFD03687C94}">Last Name</label>]
</p>
<p>Email:
[<label id="{E382A37E-9DF5-4AFE-8780-17169E687805}">Email Address</label>]
</p>
<p>Company Name:
[<label id="{9C08AC2A-4128-47F8-A998-12309B381CCD}">Company Name</label>]
</p>
<p>Phone Number:
[<label id="{4B0C5FAC-A08A-4EF2-AD3E-2B7FDF25AFA7}">Phone Number</label>]
</p>
Does anyone know what could be going wrong?
I have encountered this issue before, but was using a custom email action. I managed to fix it by not using the deprecated methods in the SendMail class and instead using the
Sitecore.Form.Core.Pipelines.ProcessMessage namespace's ProcessMessage and ProcessMessageArgs classes.
My use case was a little more complicated than yours, as we were also attaching a PDF brochure to our message (which is why we were using the custom email action in the first place), but here is the code:
public class SendBrochureEmail : SendMail, ISaveAction, ISubmit
{
public new void Execute(ID formId, AdaptedResultList fields, params object[] data)
{
try
{
var formData = new NameValueCollection();
foreach (AdaptedControlResult acr in fields)
{
formData[acr.FieldName] = acr.Value;
}
var senderName = formData["Your Name"];
var emailTo = formData["Recipient Email"];
var recipientName = formData["Recipient Name"];
var documentTitle = formData["Document Title"];
if (documentTitle.IsNullOrEmpty())
{
documentTitle = String.Format("Documents_{0}", DateTime.Now.ToString("MMddyyyy"));
}
Subject = documentTitle;
if (!String.IsNullOrEmpty(emailTo))
{
BaseSession.FromName = senderName;
BaseSession.CatalogTitle = documentTitle;
BaseSession.ToName = recipientName;
var tempUploadPath = Sitecore.Configuration.Settings.GetSetting("TempPdfUploadPath");
var strPdfFilePath =
HttpContext.Current.Server.MapPath(tempUploadPath + Guid.NewGuid().ToString() + ".pdf");
//initialize object to hold WFFM mail/message arguments
var msgArgs = new ProcessMessageArgs(formId, fields, MessageType.Email);
var theDoc = PdfDocumentGenerator.BuildPdfDoc();
theDoc.Save(strPdfFilePath);
theDoc.Clear();
FileInfo fi = null;
FileStream stream = null;
if (File.Exists(strPdfFilePath))
{
fi = new FileInfo(strPdfFilePath);
stream = fi.OpenRead();
//attach the file with the name specified by the user
msgArgs.Attachments.Add(new Attachment(stream, documentTitle + ".pdf", "application/pdf"));
}
//get the email's "from" address setting
var fromEmail = String.Empty;
var fromEmailNode = Sitecore.Configuration.Factory.GetConfigNode(".//sc.variable[#name='fromEmail']");
if (fromEmailNode != null && fromEmailNode.Attributes != null)
{
fromEmail = fromEmailNode.Attributes["value"].Value;
}
//the body of the email, as configured in the "Edit" pane for the Save Action, in Sitecore
msgArgs.Mail.Append(base.Mail);
//The from address, with the sender's name (specified by the user) in the meta
msgArgs.From = senderName + "<" + fromEmail + ">";
msgArgs.Recipient = recipientName;
msgArgs.To.Append(emailTo);
msgArgs.Subject.Append(Subject);
msgArgs.Host = Sitecore.Configuration.Settings.MailServer;
msgArgs.Port = Sitecore.Configuration.Settings.MailServerPort;
msgArgs.IsBodyHtml = true;
//initialize the message using WFFM's built-in methods
var msg = new ProcessMessage();
msg.AddAttachments(msgArgs);
msg.BuildToFromRecipient(msgArgs);
//change links to be absolute instead of relative
msg.ExpandLinks(msgArgs);
msg.AddHostToItemLink(msgArgs);
msg.AddHostToMediaItem(msgArgs);
//replace the field tokens in the email body with the user-specified values
msg.ExpandTokens(msgArgs);
msg.SendEmail(msgArgs);
//no longer need the file or the stream - safe to close stream and delete delete it
if (fi != null && stream != null)
{
stream.Close();
fi.Delete();
}
}
else
{
Log.Error("Email To is empty", this);
throw new Exception("Email To is empty");
}
}
catch (Exception ex)
{
Log.Error("Test Failed.", ex, (object) ex);
throw;
}
finally
{
BrochureItems.BrochureItemIds = null;
}
}
public void Submit(ID formid, AdaptedResultList fields)
{
Execute(formid, fields);
}
public void OnLoad(bool isPostback, RenderFormArgs args)
{
}
}
It is very possible that the Email Action that WFFM ships with is using the deprecated methods, which could be your problem. I do not have time to look into it, but you can decompile the DLL and look to see what their Email Action is doing. Regardless, the above code should work out of the box, save for updating the fields to those that you are using and removing the code for attaching the PDF, should you choose to not have attachments.
Good luck, and happy coding :)
If you change a field on the form in any way (caption, name, type, etc) the link will change and you need to re-insert the placeholder and move it up to its location in your expected email. This is also true if you duplicate a form. You'll have to reinsert all the fields in the email or you will just get the outcome you show above.
Reinserting upon a change will ensure the value is collected!

Crystal Reports - Search Dependencies

Is there a tool that will let you search a number of different crystal reports to see where a specific Table/View/SP is being used?
Scenario is this: We have over 200 reports, so when making a change to a View or Stored Procedure it is not easy to find which reports will be affected without opening each one and checking the "Database expert" or "Datasource location".
I have tried Agent Ransack on them and it doesn't pick any table or view names up.
I never found a tool to do this, so rolled my own in C# .Net 4.0.
If the crystal report uses a 'SQL Command' instead of dragging in tables, it becomes a bit tricky. I suggest only searching for the TableName rather than the fully qualified Database.dbo.TableName - since this may have been omitted in the pasted SQL Command.
usage:
var reports = CrystalExtensions.FindUsages("C:/Reports", "table_name");
code:
namespace Crystal.Helpers
{
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using CrystalDecisions.CrystalReports.Engine;
using Microsoft.CSharp.RuntimeBinder;
public static class CrystalExtensions
{
public static List<string> FindUsages(string directory, string tableName)
{
var result = new List<string>();
foreach (var file in Directory.EnumerateFiles(directory, "*.rpt", SearchOption.AllDirectories))
{
using (var report = new ReportClass { FileName = file })
{
if (report.Database == null) continue;
var tables = report.Database.Tables.ToList();
var hasTable = tables.Any(x => x.Name == tableName || x.GetCommandText().Contains(tableName));
if (hasTable)
result.Add(file);
}
}
return result;
}
public static List<Table> ToList(this Tables tables)
{
var list = new List<Table>();
var enumerator = tables.GetEnumerator();
while (enumerator.MoveNext())
list.Add((Table)enumerator.Current);
return list;
}
public static string GetCommandText(this Table table)
{
var propertyInfo = table.GetType().GetProperty("RasTable", BindingFlags.NonPublic | BindingFlags.Instance);
try
{
return ((dynamic)propertyInfo.GetValue(table, propertyInfo.GetIndexParameters())).CommandText;
}
catch (RuntimeBinderException)
{
return ""; // for simplicity of code above, really should return null
}
}
}
}
Hope that helps!
See the question here:
Any way to search inside a Crystal Report
Another option is to roll-your-own piece of software to do it, but that might be more time consuming than you're looking for. Or, find someone who already has done this :) If you find something that works, let the rest of us know because we're all in the same boat. Good luck!

DataSet does not support System.Nullable<>

i have an app which has btn to preview report made in crystal report. I added Dataset as datasource of the report and dragged datatable from the toolbox and added the fields I need as columns. I got the instruction from this link http://aspalliance.com/2049_Use_LINQ_to_Retrieve_Data_for_Your_Crystal_Reports.2. This is my 2nd report the first one works and did not encounter any prob at all that is why i am confused, not to mention it also has nullable column. the error says: DataSet does not support System.Nullable<>.
private void ShowReportView()
{
string reportFile = "JudgeInfoFMReport.rpt";
ObservableCollection<tblJudgeFileMaint> judgeFileMaintList;
judgeFileMaintList = GenerateReport();
if (judgeFileMaintList.Count > 0)
{
CrystalReportViewerUC crview2 = new CrystalReportViewerUC();
crview2.SetReportPathFile(reportFile, judgeFileMaintList);
crview2.ShowDialog();
}
else
{
System.Windows.MessageBox.Show("No record found.", module, MessageBoxButton.OK, MessageBoxImage.Information);
}
}
private ObservableCollection<tblJudgeFileMaint> GenerateReport()
{
var result = FileMaintenanceBusiness.Instance.GetAllJudgeInfoList();
return new ObservableCollection<tblJudgeFileMaint>(result);
}
The error is in the part where I set datasource report.SetDataSource
public bool SetReportPathFile(string reportPathFile, IEnumerable enumerable)
{
string reportFolder = #"\CrystalReportViewer\Reports\";
string filename = System.Windows.Forms.Application.StartupPath + reportFolder + reportPathFile; // "\\Reports\\CrystalReports\\DateWiseEmployeeInfoReport.rpt";
ReportPathFile = filename;
report.Load(ReportPathFile);
report.SetDataSource(enumerable);
report.SetDatabaseLogon("sa", "admin007");
bRet = true;
}
_IsLoaded = bRet;
return bRet;
}
I read some answers and says I should set the null value to DBNUll which I did in the properties window of each column if it is nullable. Can anyone help me please? thanks
Your question can be seen in this post, but in a generic way ... that way you can pass an Object to a DataSet typed!
.NET - Convert Generic Collection to DataTable
figured it out. by using a collectionextention, copied somewhere, I forgot the link. Os to whoever it is who made the class, credits to you.
class method looks like this.
public statis class CollectionExtension {
public static DataSet ToDataSet<T>(this IEnumerable<T> collection, string dataTableName)
{
if (collection == null)
{
throw new ArgumentNullException("collection");
}
if (string.IsNullOrEmpty(dataTableName))
{
throw new ArgumentNullException("dataTableName");
}
DataSet data = new DataSet("NewDataSet");
data.Tables.Add(FillDataTable(dataTableName, collection));
return data;
}
}
then you can use it by doing this in getting your source to your report:
private DataSet GenerateNeutralContEducReport(string dsName)
{
var contEduHistoryList = FileMaintenanceBusiness.Instance.GetManyNeutralFMContEducHistoryInfobyKeyword(CurrentNeutralFM.NeutralID, "NeutralID").ToList();
return CollectionExtensions.ToDataSet<tblContinuingEducationHistory>(contEduHistoryList, dsName);
}
I found little help from the other proposed answers but this solution worked.
A different way to solve this problem is to make the data column nullable.
DataColumn column = new DataColumn("column", Type.GetType("System.Int32"));
column.AllowDBNull = true;
dataTable.Columns.Add(column);
https://learn.microsoft.com/en-us/dotnet/api/system.data.datacolumn.allowdbnull?view=netcore-3.1
foreach (PropertyDescriptor property in properties)
{
dt.Columns.Add(property.Name, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType);
}

asp.net mvc 2 render view to string, instead of partial

I have this function:
public static string RenderViewToString(string controlName, object viewData) {
ViewDataDictionary vd = new ViewDataDictionary(viewData);
ViewPage vp = new ViewPage { ViewData = vd };
Control control = vp.LoadControl(controlName);
vp.Controls.Add(control);
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
vp.RenderControl(tw);
}
}
return sb.ToString();
}
And I call it like this:
string body = StringHelpers.RenderViewToString("~/Areas/Public/Views/Shared/RegistrationEmail.ascx", new RegistrationEmailViewModel { User = user });
And it returns a html-table with the user-info.
But I was wondering if there is a way to edit this to I can can return a View as string? so I can add masterpage, so it'll be easier to design all potential mails going out?
Thanks in advance
/M
Check out MVCContrib's email template system for sending emails.
http://codevanced.net/post/Sending-HTML-emails-with-ASPNET-MVC2-and-MVCContrib.aspx
Update:
This question and/or this article might help if you don't want to include Mvccontrib. Although I use Mvccontrib every day, it's harmless.