MVC3 Razor VS2010 ReportViewer example - asp.net-mvc-3

Can anyone point me to a working example of showing a report in mvc3 ie the full code, I have looked at some examples and they look like they are going to do the job but then just blow up, I know that a ASPX page is needed and there seems to be a good example at How can I use a reportviewer control in an asp.net mvc 3 razor view?
when I created a clean app i get Microsoft JScript runtime error: 'Microsoft' is undefined I know it is probably something simple but its been a while since I used Rdlc files so somthing showing a simple report populated via an xml datasource would be great, Thanks in advance

This is a simple task. You can follow the following steps.
Create a folder in your solution and give a name Reports.
Add a ASP.Net web form and named it ReportView.aspx
Create a Class ReportData and add it to the Reports folder. Add the following code to the Class.
public class ReportData
{
public ReportData()
{
this.ReportParameters = new List<Parameter>();
this.DataParameters = new List<Parameter>();
}
public bool IsLocal { get; set; }
public string ReportName { get; set; }
public List<Parameter> ReportParameters { get; set; }
public List<Parameter> DataParameters { get; set; }
}
public class Parameter
{
public string ParameterName { get; set; }
public string Value { get; set; }
}
Add another Class and named it ReportBasePage.cs. Add the following code in this Class.
public class ReportBasePage : System.Web.UI.Page
{
protected ReportData ReportDataObj { get; set; }
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (HttpContext.Current != null)
if (HttpContext.Current.Session["ReportData"] != null)
{
ReportDataObj = HttpContext.Current.Session["ReportData"] as ReportData;
return;
}
ReportDataObj = new ReportData();
CaptureRouteData(Page.Request);
}
private void CaptureRouteData(HttpRequest request)
{
var mode = (request.QueryString["rptmode"] + "").Trim();
ReportDataObj.IsLocal = mode == "local" ? true : false;
ReportDataObj.ReportName = request.QueryString["reportname"] + "";
string dquerystr = request.QueryString["parameters"] + "";
if (!String.IsNullOrEmpty(dquerystr.Trim()))
{
var param1 = dquerystr.Split(',');
foreach (string pm in param1)
{
var rp = new Parameter();
var kd = pm.Split('=');
if (kd[0].Substring(0, 2) == "rp")
{
rp.ParameterName = kd[0].Replace("rp", "");
if (kd.Length > 1) rp.Value = kd[1];
ReportDataObj.ReportParameters.Add(rp);
}
else if (kd[0].Substring(0, 2) == "dp")
{
rp.ParameterName = kd[0].Replace("dp", "");
if (kd.Length > 1) rp.Value = kd[1];
ReportDataObj.DataParameters.Add(rp);
}
}
}
}
}
Add ScriptManager to the ReportView.aspx page. Now Take a Report Viewer to the page. In report viewer set the property AsyncRendering="false". The code is given below.
<rsweb:ReportViewer ID="ReportViewerRSFReports" runat="server" AsyncRendering="false"
Width="1271px" Height="1000px" >
</rsweb:ReportViewer>
Add two NameSpace in ReportView.aspx.cs
using Microsoft.Reporting.WebForms;
using System.IO;
Change the System.Web.UI.Page to ReportBasePage. Just replace your code using the following.
public partial class ReportView : ReportBasePage
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
RenderReportModels(this.ReportDataObj);
}
}
private void RenderReportModels(ReportData reportData)
{
RASolarERPData dal = new RASolarERPData();
List<ClosingInventoryValuation> objClosingInventory = new List<ClosingInventoryValuation>();
// Reset report properties.
ReportViewerRSFReports.Height = Unit.Parse("100%");
ReportViewerRSFReports.Width = Unit.Parse("100%");
ReportViewerRSFReports.CssClass = "table";
// Clear out any previous datasources.
this.ReportViewerRSFReports.LocalReport.DataSources.Clear();
// Set report mode for local processing.
ReportViewerRSFReports.ProcessingMode = ProcessingMode.Local;
// Validate report source.
var rptPath = Server.MapPath(#"./Report/" + reportData.ReportName +".rdlc");
//#"E:\RSFERP_SourceCode\RASolarERP\RASolarERP\Reports\Report\" + reportData.ReportName + ".rdlc";
//Server.MapPath(#"./Report/ClosingInventory.rdlc");
if (!File.Exists(rptPath))
return;
// Set report path.
this.ReportViewerRSFReports.LocalReport.ReportPath = rptPath;
// Set report parameters.
var rpPms = ReportViewerRSFReports.LocalReport.GetParameters();
foreach (var rpm in rpPms)
{
var p = reportData.ReportParameters.SingleOrDefault(o => o.ParameterName.ToLower() == rpm.Name.ToLower());
if (p != null)
{
ReportParameter rp = new ReportParameter(rpm.Name, p.Value);
ReportViewerRSFReports.LocalReport.SetParameters(rp);
}
}
//Set data paramater for report SP execution
objClosingInventory = dal.ClosingInventoryReport(this.ReportDataObj.DataParameters[0].Value);
// Load the dataSource.
var dsmems = ReportViewerRSFReports.LocalReport.GetDataSourceNames();
ReportViewerRSFReports.LocalReport.DataSources.Add(new ReportDataSource(dsmems[0], objClosingInventory));
// Refresh the ReportViewer.
ReportViewerRSFReports.LocalReport.Refresh();
}
}
Add a Folder to the Reports Folder and named it Report. Now add a RDLC report to the Reports/Report folder and named it ClosingInventory.rdlc.
Now add a Controller and Named it ReportController. In t
o the controller add the following action method.
public ActionResult ReportViewer()
{
ViewData["reportUrl"] = "../Reports/View/local/ClosingInventory/";
return View();
}
Add a view page click on the ReportViewer Controller. Named the view page ReportViewer.cshtml. Add the following code to the view page.
#using (Html.BeginForm("Login"))
{
#Html.DropDownList("ddlYearMonthFormat", new SelectList(ViewBag.YearMonthFormat, "YearMonthValue", "YearMonthName"), new { #class = "DropDown" })
Stock In Transit: #Html.TextBox("txtStockInTransit", "", new { #class = "LogInTextBox" })
<input type="submit" onclick="return ReportValidationCheck();" name="ShowReport"
value="Show Report" />
}
Add an Iframe. Set the property of the Iframe as follows
frameborder="0" width="1000"; height="1000"; style="overflow:hidden;" scrolling="no"
Add Following JavaScript to the viewer.
function ReportValidationCheck() {
var url = $('#hdUrl').val();
var yearmonth = $('#ddlYearMonthFormat').val();
var stockInTransit = $('#txtStockInTransit').val()
if (stockInTransit == "") {
stockInTransit = 0;
}
if (yearmonth == "0") {
alert("Please Select Month Correctly.");
}
else {
//url = url + "dpSpYearMonth=" + yearmonth + ",rpYearMonth=" + yearmonth + ",rpStockInTransit=" + stockInTransit;
url = "../Reports/ReportView.aspx?rptmode=local&reportname=ClosingInventory&parameters=dpSpYearMonth=" + yearmonth + ",rpYearMonth=" + yearmonth + ",rpStockInTransit=" + stockInTransit;
var myframe = document.getElementById("ifrmReportViewer");
if (myframe !== null) {
if (myframe.src) {
myframe.src = url;
}
else if (myframe.contentWindow !== null && myframe.contentWindow.location !== null) {
myframe.contentWindow.location = url;
}
else { myframe.setAttribute('src', url); }
}
}
return false;
}
Web.config file add the following key to the appSettings section
add key="UnobtrusiveJavaScriptEnabled" value="true"
In system.web handlers Section add the following key
add verb="*" path="Reserved.ReportViewerWebControl.axd" type = "Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Change your data source as your own. This solution is very simple and I think every one enjoy it.

Related

Does the IClientValidator support input file?

Edit
I found that the problem is that View Components are unable to have an #section (see ViewComponent and #Section #2910 ) so adding custom client-side validation using the unobtrusive library seems imposible (or very complex). Moreover, the inability of including the required javascript into a View Component makes me regret of following this approach to modularize my app in the first place...
I am learning to make custom validation attributes with client-side support. I was able to implement a custom validator for a string property and it works pretty well, but when I tried to make one for input file it doesn't work (i.e. when I select a file in my computer, the application doesn't display the validation messages. The server-side validation works. Here is some code that shows my implementation.
The class of the model
public class UploadPanelModel
{
public int? ID { get; set; }
public string Title { get; set; }
public string Description { get; set; } //Raw HTML with the panel description
[FileType(type: "application/pdf")]
[FileSize(maxSize: 5000000)]
public IFormFile File { get; set; }
public byte[] FileBytes { get; set; }
public ModalModel Modal { get; set; } //Only used if the Upload panel uses a modal.
The validator
public class FileSizeAttribute : ValidationAttribute, IClientModelValidator
{
private long _MaxSize { get; set; }
public FileSizeAttribute (long maxSize)
{
_MaxSize = maxSize;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
UploadPanelModel panel = (UploadPanelModel)validationContext.ObjectInstance;
return (panel.File==null || panel.File.Length <= _MaxSize) ? ValidationResult.Success : new ValidationResult(GetFileSizeErrorMessage(_MaxSize));
}
private string GetFileSizeErrorMessage(long maxSize)
{
double megabytes = maxSize / 1000000.0;
return $"El archivo debe pesar menos de {megabytes}MB";
}
public void AddValidation(ClientModelValidationContext context)
{
if(context == null)
{
throw new ArgumentNullException(nameof(context));
}
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, "data-val-filesize", GetFileSizeErrorMessage(_MaxSize));
var maxSize = _MaxSize.ToString();
MergeAttribute(context.Attributes, "data-val-filesize-maxsize", maxSize);
}
private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
}
The javascript in the Razor View
#section Scripts{
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script type="text/javascript">
$.validator.addMethod('filesize',
function (value, element, params) {
var size = $((params[0]).val()).size(),
maxSize = params[1];
if (size < maxSize) {
return false;
}
else {
return false;
}
}
);
$.validator.unobtrusive.adapters.add('filesize',
['maxSize'],
function (options) {
var element = $(options.form).find('input#File')[0];
options.rules['filesize'] = [element, options.params['maxSize']];
options.messages['filesize'] = options.message;
}
);
</script>
I always return false in the javascript method to force the application to show the validation error regardless the chosen file, but it still doesn't work.
Your addMethod() function will be throwing an error because params[0] is not a jQuery object and has no .val() (you also have the $ in the wrong place). You would need to use
var size = params[0].files[0].size;
However I suggest you write you scripts as
$.validator.unobtrusive.adapters.add('filesize', ['maxsize'], function (options) {
options.rules['filesize'] = { maxsize: options.params.maxsize };
if (options.message) {
options.messages['filesize'] = options.message;
}
});
$.validator.addMethod("filesize", function (value, element, param) {
if (value === "") {
return true;
}
var maxsize = parseInt(param.maxsize);
if (element.files != undefined && element.files[0] != undefined && element.files[0].size != undefined) {
var filesize = parseInt(element.files[0].size);
return filesize <= maxsize ;
}
return true; // in case browser does not support HTML5 file API
});

How do you do File Upload method in AppServices for aspnetboilerplate?

I really like aspnetboilerplate framework, I learning/using it now..
How do you do 'File Upload' logic/method in AppServices for aspnetboilerplate? The angular part have I figured out and is working fine.
How is it intended to write the methods receiving a file upload in the appservice layer? There is good examples on crud, and swagger figures them out. Now I want to implement file upload. Is this even possible in the appservice layer, or do I have to do this in the controller methods?
There is no way to do that via the ApplicationServices. You need to do that in the Web project with an MVC controller and action, like you would do it in a regular project. If you need more help, I can assist.
We implement file upload method :
- use sql server fileTable technology
- implement application method's service to accept data similar to this Dto
public FileDto File { get; set; }
...
public class FileDto
{
public FileDto()
{
}
public FileDto(string file, string fileType)
{
File = file;
FileType = fileType;
}
[DisableAuditing]
public string File { get; set; }
public string FileName { get; set; }
public Guid? StreamId { get; set; }
public string FileType { get; set; } = "";
[DisableAuditing]
public string FileWithHeader
{
get
{
if (FileType == null|| FileType=="")
return "";
if (FileType.ToLower() == "jpg" || FileType.ToLower() == "jpeg")
return "data:image/Jpeg;base64," + File;
if (FileType.ToLower() == "png")
return "data:image/png;base64," + File;
if (FileType.ToLower() == "gif")
return "data:image/gif;base64," + File;
if (FileType.ToLower() == "ppt")
return "data:application/vnd.ms-powerpoint;base64," + File;
if (FileType.ToLower() == "xls")
return "data:application/vnd.ms-excel;base64," + File;
if (FileType.ToLower() == "doc")
return "data:application/msword;base64," + File;
if (FileType.ToLower() == "zip")
return "data:application/zip;base64," + File;
if (FileType.ToLower() == "exe")
return "data:application/octet-stream;base64," + File;
if (FileType.ToLower() == "txt")
return "data:text/plain;base64," + File;
if (FileType.ToLower() == "pdf")
return "data:application/pdf;base64," + File;
if (FileType.ToLower() == "bmp")
return "data:image/bmp;base64," + File;
if (FileType.ToLower() == "csv")
return "data:text/csv;base64," + File;
if (FileType.ToLower() == "pptx")
return "data:application/vnd.openxmlformats-officedocument.presentationml.presentation;base64," + File;
if (FileType.ToLower() == "xlsx")
return "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64," + File;
if (FileType.ToLower() == "docx")
return "data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64," + File;
if (FileType.ToLower() == "rar")
return "data:application/x-rar-compressed;base64," + File;
if (FileType.ToLower() == "rtf")
return "data:application/rtf;base64," + File;
return "";
}
}
}
and method implementation
public UploadFileOutput UploadFile(UploadFileInput input)
{
if (input.Id <= 0 || input.File == null)
{
throw new UserFriendlyException(L("GetDataError"));
}
return new UploadFileOutput()
{
StreamId = _attachmentRepo.InsertAttachment(input.File.FileName, Convert.FromBase64String(input.File.File), LIMSConsts.HeightThumbnail, true, ServerConfig.ThumbnailImagePath),
};
}
insertAttachment method:
public Guid InsertAttachment(string fileName, byte[] fileStream, int heightThumbnail = 50, bool saveThumbnail = false,string thumbLocationPath=null)
{
Guid AttachmentId = Guid.Empty;
SqlParameter _attachmentId = new SqlParameter();
_attachmentId.ParameterName = "#attachmentId";
_attachmentId.Direction = System.Data.ParameterDirection.InputOutput;
_attachmentId.Value = AttachmentId;
SqlParameter _fileStream = new SqlParameter();
_fileStream.SqlDbType = System.Data.SqlDbType.VarBinary;
_fileStream.Value = fileStream;
_fileStream.ParameterName = "#fileStream";
Context.Database.ExecuteSqlCommand("EXECUTE dbo.sp_AttachmentFile_Insert #AttachmentId OUTPUT,#fileName,#fileStream",
_attachmentId,
new SqlParameter("#fileName", fileName),
_fileStream);
if (saveThumbnail == true) {
var ms = new MemoryStream(fileStream);
var image = Image.FromStream(ms);
var width = (int)(heightThumbnail * image.Width / image.Height);
var height = (int)(heightThumbnail);
var Thumbnail = new Bitmap(width, height);
Graphics.FromImage(Thumbnail).DrawImage(image, 0, 0, width, height);
Bitmap Thumb= new Bitmap(Thumbnail);
Thumb.Save(Path.Combine(thumbLocationPath, _attachmentId.Value+".jpg"), ImageFormat.Jpeg);
}
return (Guid)_attachmentId.Value;
}
and Stored procedure implementation
ALTER PROC [dbo].[sp_AttachmentFile_Insert]
#AttachmentId uniqueidentifier out,
#fileName nvarchar(256),
#fileStream VARBINARY(max)
AS
SET #AttachmentId=NEWID()
WHILE(EXISTS(SELECT 1 FROM dbo.Attachment WHERE name=#fileName))
BEGIN
DECLARE #fileExtention NVARCHAR(100)
SELECT #fileExtention ='.'+dbo.GetFileExtension(#fileName)
SET #fileName=REPLACE(#fileName,#fileExtention,'')+
CAST(DATEPART( DAY, GETDATE()) AS VARCHAR(10))+'_'
+CAST(DATEPART( HOUR, GETDATE()) AS VARCHAR(10))+'_'+
+CAST(DATEPART( MINUTE, GETDATE()) AS VARCHAR(10))+'_'+
+CAST(DATEPART( SECOND, GETDATE()) AS VARCHAR(10))+#fileExtention
END
INSERT into dbo.Attachment(stream_id,name,file_stream)
VALUES(#AttachmentId,#fileName,#fileStream)
and finally Thank to "Halil İbrahim Kalkan" for thihs awesome framework.
All application services have access to the HttpContext object, so they are also able to handle file upload. To upload a file to an app. service make sure to use the correct url + headers.
App. service example:
public class MyUploadService : MyApplicationBaseClass, IMyUploadService
{
/// <summary>
/// References the logging service.
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Construct an new instance of this application service.
/// </summary>
public MyUploadService(ILogger logger)
{
_logger = logger;
}
/// <summary>
/// Method used to handle HTTP posted files.
/// </summary>
public async Task Upload()
{
// Checking if files are sent to this app service.
if(HttpContext.Current.Request.Files.Count == 0)
throw new UserFriendlyException("No files given.");
// Processing each given file.
foreach(var file in HttpContext.Current.Request.Files)
{
// Reading out meta info.
var fileName = file.fileName;
var extension = Path.GetExtension(file.FileName);
// Storing file on disk.
file.SaveAs("~/uploads");
}
}
}
There is no way to upload a file from Appservice you need to create a web Api controler with a particular method for this action.
public class EntityImageController : AbpApiController
{
private IEntityImageAppService iEntityAppService;
public EntityImageController( IEntityImageAppService pEntityImgAppService ) : base()
{
this.LocalizationSourceName = AppConsts.LocalizationSourceName;
this.iEntityImgAppService = pEntityImgAppService;
}
[AbpAuthorize( PermissionNames.Entity_Update )]
[HttpPost]
public async Task<HttpResponseMessage> Set()
{
// Check if the request contains multipart/form-data.
if( !Request.Content.IsMimeMultipartContent() )
{
throw new HttpResponseException( HttpStatusCode.UnsupportedMediaType );
}
string root = HttpContext.Current.Server.MapPath( "~/App_Data" );
var provider = new MultipartFormDataStreamProvider( root );
try
{
// Read the form data.
await Request.Content.ReadAsMultipartAsync( provider );
var mEntityId = provider.FormData[ "EntityId" ];
MultipartFileData mFileData = provider.FileData.FirstOrDefault();
var mFileInfo = new FileInfo( mFileData.LocalFileName );
var mImageBytes = File.ReadAllBytes( mFileInfo.FullName );
await this.iEntityImgAppService.Set( new EntityImageInput
{
ImageInfo = mImageBytes,
EntityId = Convert.ToInt32( mEntityId )
} );
return Request.CreateResponse( HttpStatusCode.OK );
}
catch( System.Exception e )
{
return Request.CreateErrorResponse( HttpStatusCode.InternalServerError, e );
}
}
}
Create a file upload controller in the web.core project.
Then reference your appService to process the file.
[HttpPost]
[AbpMvcAuthorize(PermissionNames.TenantPageJob)]
public async Task UploadExcelJobs()
{
var files = Request.Form.Files;
foreach (var file in files)
{
if (file.Length > 0 && file.ContentType.Contains("excel"))
{
var targetPath = Path.Combine(Path.GetTempPath(), (new Guid().ToString()), file.FileName);
var fs = new FileStream(targetPath, FileMode.OpenOrCreate);
await file.CopyToAsync(fs);
await _myAppService.ProcessFile(targetPath);
System.IO.File.Delete(targetPath);
}
}
}
The point is is how to get the files from the method of the class XXXAppService which derived from ApplicationService, not from the XXXController which derived from AbpController or Microsoft.AspNetCore.Mvc.Controller.
So you should remember the class: HttpContext/HtttpRequest/HttpResponse!!!
Solution: Inject httpContextAccessor in the class XXXAppService will achive it.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-5.0
Here is my codes, wish will help you!
------Server side (ABP)--------------
[Route("api/")]
public class XXXAppService : ApplicationService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public XXXAppService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
[HttpPost, Route("upload")]
public void UploadFile()
{
var files = _httpContextAccessor.HttpContext.Request.Form.Files;
//do logics as you like here...
}
}
---(1) UI (PrimeNG upload component)
<p-fileUpload name="demo[]" [multiple]="true" [url]="uploadUrl"
(onUpload)="onUpload($event)">
<ng-template pTemplate="content">
<ul *ngIf="uploadedFiles.length">
<li *ngFor="let file of uploadedFiles">{{file.name}} - {{file.size / 1000}}kb</li>
</ul>
</ng-template>
</p-fileUpload>
---(2) UI logic (component)
import { AppConsts } from '#shared/AppConsts';
uploadUrl: string = '';
uploadedFiles: any[] = [];
ngOnInit() {
//http://localhost:21021/api/upload
let url_ = AppConsts.remoteServiceBaseUrl + "/api/upload";
this.uploadUrl = url_.replace(/[?&]$/, "");
}
onUpload(event: any) {
_.forEach(event.files, v => {
this.uploadedFiles.push(v);
});
}

conversion Error from String to System.Web.Mvc.ViewResult in MVC3

Hi I am quite new on MVC and I am trying to create a simple conversion from Fahrenheit to Celsius along with its unit testing. Sorry in advance for putting all the code here.
This is my controller code:
public string Convert(double value,string option)
{
string d;
if(option=="1") {
d = " To Celcius"+FahrenheitToCelsius(value).ToString();
}
else {
d = " To Fahrenheit" + CelsiusToFahrenheit(value).ToString();
}
return "ConvertTo" + d;
}
public static double CelsiusToFahrenheit(double temperatureCelsius)
{
double celsius = temperatureCelsius;
return (celsius * 9 / 5) + 32;
}
public static double FahrenheitToCelsius (double temperatureFahrenheit)
{
double fahrenheit = temperatureFahrenheit;
return (fahrenheit - 32) * 5 / 9;
}
This is my View Page
protected void btnConvert(object sender, EventArgs e)
{
if (DropDownList1.SelectedValue=="1"){
double temp = TemperatureConverterController.FahrenheitToCelsius(double.Parse(TextBox1.Text));
Literal1.Text = temp.ToString();
}
else{
double temp = TemperatureConverterController.CelsiusToFahrenheit(double.Parse(TextBox1.Text));
Literal1.Text = temp.ToString();
Literal1.Text = temp.ToString();
}
}
When i do this unit testing i got an error:
[TestMethod]
public void ConvertReturnsAViewResultWhenInputDataIsValid()
{
//Arrange
var controller = new TemperatureConverterController();
//Act
double x = 80;
double y = 25;
var result = controller.Convert(x, "1") as ViewResult;
// here i get this error under ViewResult //
//Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
}
[TestMethod]
public void ConvertAsksForAViewTemplateNamedConvert()
{
//Arrange
var controller = new TemperatureConverterController();
String expectedViewTemplate = "Convert";
//Act
double x = 80;
double y = 25;
var result = controller.Convert(x, "1") as ViewResult;
////Assert
Assert.AreEqual<String>(expectedViewTemplate, result.ViewName);
}
Error is:
Error Cannot convert type 'string' to 'System.Web.Mvc.ViewResult' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion.
the problem is here
var result = controller.Convert(x, "1") as ViewResult;
your Convert method is returning string and you are casting it as ViewResult
Your convert method should looks like
public ActionResult Convert()
{
//Make a Model class and pass it to View
//...
return View(model_class_object);
}
Alternatively you can make controller like this
public ActionResult Convert()
{
ViewData["tempvalue"]=Convert(x, "1");
//Make a Model class and pass it to View
//...
return View();
}
and on your View you can just print it
#ViewData["tempvalue"].ToString()
In MVC the controller code should return an "ActionResult" object containing the model.
If the data you want to pass to view is simply a string use:
public ActionResult Convert()
{
//...
return View("your result here...");
}
You can refer to data returned by controller using the "Model" property in Views or Tests.
Let's go backwards for a minute here.
Controller
public class ConvertController : Controller
{
public ActionResult Convert(MyConvertViewModel vm)
{
if (vm == null) { return View("convert", new MyConvertViewModel { ShowResult = false }); }
if (vm.Option == 1)
{
vm.Result = FahrenheitToCelsius(vm.Input);
vm.OptionName = "Fahrenheit To Celsius";
}
else
{
vm.Result = CelsiusToFahrenheit(vm.Input);
vm.OptionName = "Celsius to Fahrenheit";
}
vm.ShowResult = true;
//not needed, just for an example
ViewData.Add("glosrob-example", "A value goes here!");
return View("convert", vm);
}
private static double CelsiusToFahrenheit(double temperatureCelsius)
{
double celsius = temperatureCelsius;
return (celsius * 9 / 5) + 32;
}
private static double FahrenheitToCelsius(double temperatureFahrenheit)
{
double fahrenheit = temperatureFahrenheit;
return (fahrenheit - 32)*5/9;
}
}
public class MyConvertViewModel
{
public double Result { get; set; }
public int Option { get; set; }
public double Input { get; set; }
public string OptionName { get; set; }
public bool ShowResult { get; set; }
}
View
#model MvcApplication1.Controllers.MyConvertViewModel
#{
ViewBag.Title = "Convert";
}
<h2>Convert</h2>
#using (Html.BeginForm("convert", "convert", FormMethod.Post))
{
<div>
Let's convert some temperatures!
</div>
<div>
#Html.LabelFor(x => x.Input, "Temp. To Convert")
#Html.TextBoxFor(x => x.Input)
</div>
<div>
#Html.LabelFor(x => x.Option, "Convert to ")
#Html.DropDownListFor(x => x.Option, new List<SelectListItem>
{
new SelectListItem {Text = "Celsius", Value = "1"},
new SelectListItem {Text = "Fahrenheit", Value = "2"}
})
</div>
<div>
<button type="submit">Convert It!</button>
</div>
}
#if (Model.ShowResult)
{
<p>#Model.OptionName : #Model.Input = #Model.Result</p>
}
disclaimer: there is a lot of shortcuts there, it is only included to give you an idea of what you should have.
So the view will post back data the user chooses, to the controller action Convert
The controller in turn will return a ViewResult object, and it will be rendered using the data captured in the view model MyConvertViewModel
Now we want to test this.
So here are some of the more important properties that it seems like you need to hook into
[TestMethod]
public void Not_A_Real_Test_But_Stuff_You_Will_Want_To_Use()
{
//arrange
var c = new ConvertController();
//act
var results = c.Convert(null) as ViewResult;
//now results is a ViewResult or null
var theViewModelProperty = results.Model as MyConvertViewModel;
var exampleResult = theViewModelProperty.Result;
var exampleInput = theViewModelProperty.Input;
//etc
//how about the view that was returned?
var theViewName = results.ViewName;
//or anything you put in the ViewData
var theViewData = results.ViewData["glosrob-example"];
Assert.Fail("This was not a real test!");
}
Hopefully this gives you an idea of how you can test for output from a controller method.
Edit: I'm not writing all your tests for you but as an e.g.
[TestMethod]
public void Convert_Should_Return_A_MyConvertViewModel()
{
//arrange
var c = new Controller();
//act
var result = c.Convert(null) as ViewResult;
//assert
Assert.IsNotNull(result);
Assert.IsInstanceOfType(result.ViewModel, typeof(MyConvertViewModel));
}
[TestMethod]
public void Convert_Should_Return_The_Correct_View()
{
//arrange
var c = new Controller();
//act
var result = c.Convert(null) as ViewResult;
//assert
Assert.IsNotNull(result);
Assert.AreEqual("convert", result.ViewName);
}

How to restrict the file types in FileUpload in MVC3?

I have a fileupload function where users can upload files. I want to restrict the users from upload certain file types. The types allowed are: .doc,.xlsx,.txt,.jpeg.
How I can do this?
This is my actual file upload code:
public ActionResult UploadFile(string AttachmentName, BugModel model)
{
BugModel bug = null;
if (Session["CaptureData"] == null)
{
bug = model;
}
else
{
bug = (BugModel)Session["CaptureData"];
}
foreach (string inputTagName in Request.Files)
{
HttpPostedFileBase file1 = Request.Files[inputTagName];
if (file1.ContentLength > 0)
{
string path = "/Content/UploadedFiles/" + Path.GetFileName(file1.FileName);
string savedFileName = Path.Combine(Server.MapPath("~" + path));
file1.SaveAs(savedFileName);
BugAttachment attachment = new BugAttachment();
attachment.FileName = "~" + path.ToString();
attachment.AttachmentName = AttachmentName;
attachment.AttachmentUrl = attachment.FileName;
bug.ListFile.Add(attachment);
model = bug;
Session["CaptureData"] = model;
}
}
ModelState.Clear();
return View("LoadBug", bug);
}
The first thing to verify is whether the file extension contained in file1.FileName matches one of the allowed extensions. Then if you really want to ensure that the user hasn't renamed some other file type to an allowed extension you will need to look into the contents of the file to recognize whether it is one of the allowed types.
Here's an example how to check whether the file extension belongs to a list of predefined extensions:
var allowedExtensions = new[] { ".doc", ".xlsx", ".txt", ".jpeg" };
var extension = Path.GetExtension(file1.FileName);
if (!allowedExtensions.Contains(extension))
{
// Not allowed
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class AllowedFileExtensionAttribute : ValidationAttribute
{
public string[] AllowedFileExtensions { get; private set; }
public AllowedFileExtensionAttribute(params string[] allowedFileExtensions)
{
AllowedFileExtensions = allowedFileExtensions;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var file = value as HttpPostedFileBase;
if (file != null)
{
if (!AllowedFileExtensions.Any(item => file.FileName.EndsWith(item, StringComparison.OrdinalIgnoreCase)))
{
return new ValidationResult(string.Format("{1} için izin verilen dosya uzantıları : {0} : {2}", string.Join(", ", AllowedFileExtensions), validationContext.DisplayName, this.ErrorMessage));
}
}
return null;
}
}
Usage In Model
[AllowedFileExtension(".jpg", ".png", ".gif", ".jpeg")]
public HttpPostedFileBase KategoriResmi { get; set; }
You can use the ContentType property of the HttpPostedFileBase for a basic check of the file type (mime type): See MSDN's page on the Content-Type property here
Here is one way to do it:
private static bool IsValidContentType(string contentType)
{
string ct = contentType.ToLower();
return ((ct == "application/msword") || (ct == "application/pdf") || (ct == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"));
}
etc..
However, for a deeper inspection, you will have to inspect the file content. It's easy to change a file extension..

How to use Razor Section multiple times in a View & PartialView (merge) without overriding it?

In the _Layout.cshtml file, I have a section at the bottom of the body called "ScriptsContent" declared like this:
#RenderSection("ScriptsContent", required: false)
In my view, I can then use this section to add scripts to be executed. But what if I also have a PartialView that also need to use this section to add additional scripts?
View
#section ScriptsContent
{
<script type="text/javascript">
alert(1);
</script>
}
#Html.Partial("PartialView")
PartialView
#section ScriptsContent
{
<script type="text/javascript">
alert(2);
</script>
}
Result
Only the first script is rendered. The second script doesn't exist in source code of the webpage.
Razor seems to only output the first #section ScriptsContent that it sees. What I would like to know is if there's a way to merge each call to the section.
If we cannot do this, what do you propose?
Here's a solution for that problem. It's from this blog: http://blog.logrythmik.com/post/A-Script-Block-Templated-Delegate-for-Inline-Scripts-in-Razor-Partials.aspx
public static class ViewPageExtensions
{
private const string SCRIPTBLOCK_BUILDER = "ScriptBlockBuilder";
public static MvcHtmlString ScriptBlock(this WebViewPage webPage, Func<dynamic, HelperResult> template)
{
if (!webPage.IsAjax)
{
var scriptBuilder = webPage.Context.Items[SCRIPTBLOCK_BUILDER] as StringBuilder ?? new StringBuilder();
scriptBuilder.Append(template(null).ToHtmlString());
webPage.Context.Items[SCRIPTBLOCK_BUILDER] = scriptBuilder;
return new MvcHtmlString(string.Empty);
}
return new MvcHtmlString(template(null).ToHtmlString());
}
public static MvcHtmlString WriteScriptBlocks(this WebViewPage webPage)
{
var scriptBuilder = webPage.Context.Items[SCRIPTBLOCK_BUILDER] as StringBuilder ?? new StringBuilder();
return new MvcHtmlString(scriptBuilder.ToString());
}
}
so anywwhere in your View or PartialView you can use this:
#this.ScriptBlock(
#<script type='text/javascript'>
alert(1);
</script>
)
and in your _Layout or MasterView, use this:
#this.WriteScriptBlocks()
There is no way to share sections between a view and partial views.
Absent a ScriptManager-like solution, you could have a collection of script files (initialized in your view and stored either in HttpContext.Items or in ViewData) to which the partial view would append the script file names it requires. Then towards the end of your view you would declare a section that fetches that collection and emits the right script tags.
The problem with the accepted answer is that it breaks Output Caching. The trick to solving this is to overwrite the OutputCache attribute with your own implementation. Unfortunately we can't extend the original attribute since it has lots of internal methods which we need to access.
I actually use Donut Output Caching which overwrites the OutputCache attribute itself. There are alternative libraries which also use their own OutputCache attribute so I will explain the steps I made to get it to work so that you can apply it to whichever one you're using.
First you need to copy the existing OutputCache attribute and place it within your application. You can get the existing attribute by looking at the source code.
Now add the following property to the class. This is where we store the script blocks so we can render the correct ones when retrieving from the cache.
public static ConcurrentDictionary<string, StringBuilder> ScriptBlocks = new ConcurrentDictionary<string, StringBuilder>();
Now inside the OnActionExecuting method you need to store the cache key (the unique identifier for the output cache) inside the current requests collection. For example:
filterContext.HttpContext.Items["OutputCacheKey"] = cacheKey;
Now modify the ViewPageExtensions class by adding the following (replacing CustomOutputCacheAttribute with the name of your attribute):
var outputCacheKey = webPage.Context.Items["OutputCacheKey"] as string;
if (outputCacheKey != null)
CustomOutputCacheAttribute.ScriptBlocks.AddOrUpdate(outputCacheKey, new StringBuilder(template(null).ToHtmlString()), (k, sb) => {
sb.Append(template(null).ToHtmlString());
return sb;
});
before:
return new MvcHtmlString(string.Empty);
Note: For a slight performance boost you'll also want to make sure you only call "template(null).ToHtmlString()" once.
Now return to your custom OutputCache attribute and add the following only when you are retrieving from the cache inside the OnActionExecuting method:
if (ScriptBlocks.ContainsKey(cacheKey)) {
var scriptBuilder = filterContext.HttpContext.Items["ScriptBlockBuilder"] as StringBuilder ?? new StringBuilder();
scriptBuilder.Append(ScriptBlocks[cacheKey].ToString());
filterContext.HttpContext.Items["ScriptBlockBuilder"] = scriptBuilder;
}
Here's the final code of my attribute:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
using DevTrends.MvcDonutCaching;
public class CustomOutputCacheAttribute : ActionFilterAttribute, IExceptionFilter {
private readonly IKeyGenerator _keyGenerator;
private readonly IDonutHoleFiller _donutHoleFiller;
private readonly IExtendedOutputCacheManager _outputCacheManager;
private readonly ICacheSettingsManager _cacheSettingsManager;
private readonly ICacheHeadersHelper _cacheHeadersHelper;
private bool? _noStore;
private CacheSettings _cacheSettings;
public int Duration { get; set; }
public string VaryByParam { get; set; }
public string VaryByCustom { get; set; }
public string CacheProfile { get; set; }
public OutputCacheLocation Location { get; set; }
public bool NoStore {
get { return _noStore ?? false; }
set { _noStore = value; }
}
public static ConcurrentDictionary<string, StringBuilder> ScriptBlocks = new ConcurrentDictionary<string, StringBuilder>();
public DonutOutputCacheAttribute() {
var keyBuilder = new KeyBuilder();
_keyGenerator = new KeyGenerator(keyBuilder);
_donutHoleFiller = new DonutHoleFiller(new EncryptingActionSettingsSerialiser(new ActionSettingsSerialiser(), new Encryptor()));
_outputCacheManager = new OutputCacheManager(OutputCache.Instance, keyBuilder);
_cacheSettingsManager = new CacheSettingsManager();
_cacheHeadersHelper = new CacheHeadersHelper();
Duration = -1;
Location = (OutputCacheLocation)(-1);
}
public override void OnActionExecuting(ActionExecutingContext filterContext) {
_cacheSettings = BuildCacheSettings();
var cacheKey = _keyGenerator.GenerateKey(filterContext, _cacheSettings);
if (_cacheSettings.IsServerCachingEnabled) {
var cachedItem = _outputCacheManager.GetItem(cacheKey);
if (cachedItem != null) {
filterContext.Result = new ContentResult {
Content = _donutHoleFiller.ReplaceDonutHoleContent(cachedItem.Content, filterContext),
ContentType = cachedItem.ContentType
};
if (ScriptBlocks.ContainsKey(cacheKey)) {
var scriptBuilder = filterContext.HttpContext.Items["ScriptBlockBuilder"] as StringBuilder ?? new StringBuilder();
scriptBuilder.Append(ScriptBlocks[cacheKey].ToString());
filterContext.HttpContext.Items["ScriptBlockBuilder"] = scriptBuilder;
}
}
}
if (filterContext.Result == null) {
filterContext.HttpContext.Items["OutputCacheKey"] = cacheKey;
var cachingWriter = new StringWriter(CultureInfo.InvariantCulture);
var originalWriter = filterContext.HttpContext.Response.Output;
filterContext.HttpContext.Response.Output = cachingWriter;
filterContext.HttpContext.Items[cacheKey] = new Action<bool>(hasErrors => {
filterContext.HttpContext.Items.Remove(cacheKey);
filterContext.HttpContext.Response.Output = originalWriter;
if (!hasErrors) {
var cacheItem = new CacheItem {
Content = cachingWriter.ToString(),
ContentType = filterContext.HttpContext.Response.ContentType
};
filterContext.HttpContext.Response.Write(_donutHoleFiller.RemoveDonutHoleWrappers(cacheItem.Content, filterContext));
if (_cacheSettings.IsServerCachingEnabled && filterContext.HttpContext.Response.StatusCode == 200)
_outputCacheManager.AddItem(cacheKey, cacheItem, DateTime.UtcNow.AddSeconds(_cacheSettings.Duration));
}
});
}
}
public override void OnResultExecuted(ResultExecutedContext filterContext) {
ExecuteCallback(filterContext, false);
if (!filterContext.IsChildAction)
_cacheHeadersHelper.SetCacheHeaders(filterContext.HttpContext.Response, _cacheSettings);
}
public void OnException(ExceptionContext filterContext) {
if (_cacheSettings != null)
ExecuteCallback(filterContext, true);
}
private void ExecuteCallback(ControllerContext context, bool hasErrors) {
var cacheKey = _keyGenerator.GenerateKey(context, _cacheSettings);
var callback = context.HttpContext.Items[cacheKey] as Action<bool>;
if (callback != null)
callback.Invoke(hasErrors);
}
private CacheSettings BuildCacheSettings() {
CacheSettings cacheSettings;
if (string.IsNullOrEmpty(CacheProfile)) {
cacheSettings = new CacheSettings {
IsCachingEnabled = _cacheSettingsManager.IsCachingEnabledGlobally,
Duration = Duration,
VaryByCustom = VaryByCustom,
VaryByParam = VaryByParam,
Location = (int)Location == -1 ? OutputCacheLocation.Server : Location,
NoStore = NoStore
};
} else {
var cacheProfile = _cacheSettingsManager.RetrieveOutputCacheProfile(CacheProfile);
cacheSettings = new CacheSettings {
IsCachingEnabled = _cacheSettingsManager.IsCachingEnabledGlobally && cacheProfile.Enabled,
Duration = Duration == -1 ? cacheProfile.Duration : Duration,
VaryByCustom = VaryByCustom ?? cacheProfile.VaryByCustom,
VaryByParam = VaryByParam ?? cacheProfile.VaryByParam,
Location = (int)Location == -1 ? ((int)cacheProfile.Location == -1 ? OutputCacheLocation.Server : cacheProfile.Location) : Location,
NoStore = _noStore.HasValue ? _noStore.Value : cacheProfile.NoStore
};
}
if (cacheSettings.Duration == -1)
throw new HttpException("The directive or the configuration settings profile must specify the 'duration' attribute.");
if (cacheSettings.Duration < 0)
throw new HttpException("The 'duration' attribute must have a value that is greater than or equal to zero.");
return cacheSettings;
}
}
I also had to modify the Donut Output Cache library to make IExtendedOutputCacheManager and the OutputCacheManager constructor public.
Please note this has been extracted from my application and may require some minor tweaks. You should also place WriteScriptBlocks at the bottom of the page so it is not called until after all child actions are triggered.
Hope this helps.

Resources