session value becoming null on postback and page refresh - c#

In my webpage I'm not able to get the session variable on post back and page resfresh.
The problem is
if the page is not IsPostback then I'm able to get the session variable.
But if the page postback then the error appears.
This error comes when i upload any file to server.I am using asynchfileupload to upload a image and store it to a session variable. and later on button click i am saving data to directory.
but it is not occuring frequently.
here is my code
protected void AsynImageLoader_UploadedComplete(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
if (AsynImageLoader.PostedFile != null)
{
string extension = System.IO.Path.GetExtension(AsynImageLoader.PostedFile.FileName);
if (extension == ".jpg" || extension == ".gif" || extension == ".jpeg" || extension == ".png")
{
HttpPostedFile file = AsynImageLoader.PostedFile;
Session["TempImage"] = ReadFile(file);
}
}
}
on button click
var storedImage = Session["TempImage"] as byte[];
String Strthumbpath = Server.MapPath("content\\thumbnail\\");
if (storedImage != null)
{
System.Drawing.Image image = GetImage(storedImage);
if (image != null)
{
image.Save(Strthumbpath + strFileName);
}
}
///inserting values to datbase.
after somuch googling i read that when any files is adding to any sub directory or editing the webconfig will cause cause the application to restart.
if so how can i solve this..
thanks in advance.

Well, i've just tested with ASP.NET MVC, it works fine for me.
What i did was craete two actions, one for setting session variable, another for creating file, so i've modified default asp.net mvc application home controller to this:
public ActionResult Index()
{
ViewBag.Message = Session["Sample"];
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult AddSessionVariable()
{
Session["Sample"] = "Sample session variable";
return RedirectToAction("Index");
}
public ActionResult CreateFile()
{
var bmp = new Bitmap(100, 100);
bmp.Save(Server.MapPath(string.Format(#"\Images\{0}", DateTime.Now.Ticks)));
return RedirectToAction("Index");
}
So, when I go to AddSessionVriable, it adds something to session and index action renders that session variable to page, that i could see, that it is not gone. Then I go to create file and my session variable is still there, so that does not restart application. I'm pretty sure, that Web Forms application works the same way, may be you're loosing some exception (for example because of missing permissions) when saving file and that restarts your application.

Don't save uploaded files inside your virtual folder for the web application.
This also reduces the security risk (now, people could potentially upload an asp page, including embedded code, and access it if they can manufacture the URL (which could be dead simple)).

Related

Cannot delete file from server folder

I'm working on a simple portfolio project. I would like to show images on a webpage that logged in users can edit. My problem is in the [HttpPost] Edit, more specifically this part:
if (ModelState.IsValid)
{
//updating current info
inDb = ModelFactory<ArtSCEn>.GetModel(db, artSCEn.ArtSCEnID);
inDb.LastModified = DateTime.Now;
inDb.TechUsed = artSCEn.TechUsed;
inDb.DateOfCreation = artSCEn.DateOfCreation;
inDb.Description = artSCEn.Description;
inDb.ArtSC.LastModified = DateTime.Now;
//validating img
if (Validator.ValidateImage(img))
{
inDb.ImageString = Image.JsonSerialzeImage(img);
}
else
{
//return to the UI becuase we NEED a valid pic
return View(artSCEn);
}
db.Entry(inDb).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
//[PROBLEMATIC PART STARTS HERE]
//updating the pic on the server
//getting the string info
string userArtImgFolder = Server.MapPath($"~/Content/Images/Artistic/{inDb.ArtSC.PersonID}");
string imgNameOnServer = Path.Combine(
userArtImgFolder,
$"{inDb.ArtSC.PersonID}_{inDb.ArtSC.ArtSCID}_{inDb.ArtSCEnID}{Path.GetExtension(img.FileName)}");
//deleting previous pic
System.IO.File.Delete(imgNameOnServer);
//creating a new pic
Image.ResizePropotionatelyAndSave(img, Path.Combine(
userArtImgFolder,
$"{inDb.ArtSC.PersonID}_{inDb.ArtSC.ArtSCID}_{inDb.ArtSCEnID}{Path.GetExtension(img.FileName)}"));
return RedirectToAction("Edit", "Art", new { id = inDb.ArtSCID });
}
When I get back the new picture and I want to delete the previous, System.IO.File.Delete() always triggers an exception that it cannot access the resource, because someone else is holding onto it. Any idea what that might be?
Maybe it's something simple, I'm new to ASP, but just can't figure it out.
UPDATE
Following on the suggestions in the comments section, I checked the processes with a tool called Process Monitor and it seems that indeed IIS is locking the resource:
This one appears 2 more times in the logs, by the way.
Judging by the fact that the operation is CreateFileMapping, I guess it has to do with either Server.MapPath() or Path.Combine(), however, the Server is an IDisposable (being derived from Controller), so can that be the one I should deal with?
Also, the resource I'm trying to delete is an image used on the website, which might be a problem, but that section of the website is not shown during this process.
I found the solution building on the comment of #Diablo.
The IIS was indeed holding on to the resource, but Server.MapPath() or any of that code had nothing to do with it: it was the Edit view my page returning the data to. With the help of this SO answer, it turns out I was careless with a BitMap that I used without a using statement in the view to get some image stats. I updated the helper function with the following code:
public static float GetImageWidthFromPath(string imgAbsolutPath, int offset)
{
float width = 0;
using (Bitmap b = new Bitmap(imgAbsolutPath))
{
width = b.Width - offset;
}
return width;
}
Now IIS does not hold on to the resource and I can delete the file.

MVC Global variables reseting to null when entering another action method

public class MusicController : Controller
{
User currentUser;
public PartialViewResult UploadMusic()
{
return PartialView("_UploadMusic");
}
[HttpPost]
public ActionResult UploadMusic(List<HttpPostedFileBase> files)
{
EntityDBContext db = new EntityDBContext();
List<Song> uploadedSongs = new List<Song>();
foreach (var file in files)
{
if (file != null)
{
string songName = Path.GetFileName(file.FileName);
byte[] songAsBytes = new byte[file.ContentLength];
using (BinaryReader br = new BinaryReader(file.InputStream))
{
songAsBytes = br.ReadBytes(file.ContentLength);
}
//Save new record in database
Song song = new Song
{
SongName = songName,
SongBytes = songAsBytes
};
uploadedSongs.Add(song);
}
}
string userName = User.Identity.Name;
currentUser = db.Users.Where(x => x.Username == userName).First();
currentUser.UserSongs = uploadedSongs;
return ShowSongs(currentUser.UserSongs);
}
public ActionResult ShowSongs(List<Song> UserSongs)
{
return View("ShowSongs", UserSongs);
}
public ActionResult Publish()
{
EntityDBContext db = new EntityDBContext();
foreach (var song in currentUser.UserSongs)
{
if (song != null)
{
db.Songs.Add(song);
db.SaveChanges();
}
}
return View();
}
}
ShowSongs view:
#model List<Vidafo.Models.Song>
#Html.ActionLink("Publish", "Publish")
The Problem
So I declare currentUser at the top of the controller. I then assign a value to that with this line here currentUser.UserSongs = uploadedSongs; This works fine but when the code goes into Publish() currentUser.UserSongs is null.
I need to have access to currentUser.UserSongs in more than one action method after assigning a value but it seems that it resets to null when it enters another action.
Object state isn't maintained across requests, that's not how web applications work. Every time a request is sent to the server, a new instance of the controller object is created. So any instance-level values are new.
In order to persist information across requests you need to persist it somewhere. For something like a user context, session state is a common choice. You'll probably want to wrap it in a common provider interface so as to not couple your controllers to an HTTP context, but at its core storing in session is simple:
HttpContext.Current.Session["someKey"] = someValue;
(You could even re-fetch from the database with each request. It's slightly less performant, but very simple and robust.)
Don't count out the ASP.NET identity system for this, though. ASP.NET is pretty good at abstracting a lot of this for you. You're already using it here:
string userName = User.Identity.Name;
Then you use that value to get the user from the database. You could extend the identity system to store a custom user object which fits your needs. But that's a larger scope effort outside of this question.
For this you can make use of TempData i.e. store value in TempData dictionary. One problem here is MVC doesn't sore value of variable during postback i.e. during different action of same controller or calling another controller for this you can use temporary varialble TempData as suggested.

Adding Image MediaType programatically Umbraco 7.1

Im a bit new to Umbraco, and i have to say i like it a lot.
But now i'm stuck on something simple i think. I Created a protected page that is only visible to members on my website. Where the member is able to upload multiple files at once. This is al working like a charm. First i created the upload form for multiple images then i created the SurfaceController to handle the submit. Also working like a charm.
My ActionResult on my SurfaceController receives an IEnumerable<HttpPostedFileBase> called files which is good. I see all my images that i'm posting with my form. But here comes the problem.
While looping over my files I try to create a Media (Image type) using the MediaService.CreateMedia giving my filename and parentid and the mediaType (Image).
But when i try to set the umbracoFile value on my just created media item i will get the following exception:
An unhandled exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Umbraco.Core.dll
Additional information: The best overloaded method match for
'Umbraco.Core.Models.ContentBase.SetPropertyValue(string, string)'
has some invalid arguments
I hope someone can tell my what i'm doing wrong. Below is my code i'm using
[HttpPost]
public ActionResult UploadFiles(IEnumerable<HttpPostedFileBase> files)
{
bool success = false;
//Get logged in member and look for the mediafolderID
var member = Services.MemberService.GetByUsername(HttpContext.User.Identity.Name);
var mediaFolderID = member.GetValue<int>("mediaFolderID");
//Get mediafolder
var mediaFolder = Services.MediaService.GetById(mediaFolderID);
try
{
// Create a media item from each file uploaded
foreach (var file in files)
{
var fileName = file.FileName; // Assumes no path information, just the file name
var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower();
if (!UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles.Contains(ext))
{
var mediaType = global::Umbraco.Core.Constants.Conventions.MediaTypes.File;
if (UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes.Contains(ext))
{
mediaType = global::Umbraco.Core.Constants.Conventions.MediaTypes.Image;
}
var f = Services.MediaService.CreateMedia(fileName, mediaFolderID, mediaType);
// Assumes the file.InputStream is a Stream - you may have to do some extra work here...
f.SetValue(global::Umbraco.Core.Constants.Conventions.Media.File,(Stream)file.InputStream); // Real magic happens here.
Services.MediaService.Save(f);
}
}
success = true;
}
catch (Exception ex)
{
// On error show message
ViewData["exceptionMessage"] = ex.Message;
success = false;
}
// On success redirect to current page and show successmessage
ViewData["success"] = success;
if (success)
{
return RedirectToCurrentUmbracoPage();
}
return CurrentUmbracoPage();
}
Instead of f.SetValue(global::Umbraco.Core.Constants.Conventions.Media.File, (Stream)file.InputStream); you should just use the HttpPostedFileBase: f.SetValue(global::Umbraco.Core.Constants.Conventions.Media.File, file);
Some other notes:
Check that the file has a length and is not null: file != null && file.ContentLength > 0
You're not using your mediaFolder variable anywhere, can be removed.
Not sure why you'd need global::Umbraco.Core, consider adding using Umbraco.Core; and use Constants.Conventions.MediaTypes.Image etc.
Check that you really need to rely on DisallowedUploadFiles - I'm pretty sure that's checked during CreateMedia

MVC Stream outputting to HTML div

Small problem here with an MVC app that I'm not sure how to figure out a way around.
Basically, I'm adding additional functionality to a system that was originally created by someone else (c#). For a reporting system, the results were only ever displayed on screen. Now I am building in the functionality to allow the user the ability to download their report as an Excel document.
So basically, I have a view that displays the date ranges, and some other search refinement options to the user. I have introduced a radio button that if selected will download the report as opposed to displaying it on screen.
Here are my three actions within the ReportController:
public ActionResult Index()
{
return View();
}
public ActionResult ProductReport(AdminReportRequest reportRequest, FormCollection formVariables)
{
AdminEngine re = new AdminEngine();
if (!reportRequest.Download)
{
AdminReport report = re.GetCompleteAdminReport(reportRequest);
return View(report);
}
Stream ExcelReport = re.GetExcelAdminReport(reportRequest);
TempData["excelReport"] = ExcelReport;
return RedirectToAction("ExcelProductReport");
}
public FileResult ExcelReport()
{
var ExcelReport = TempData["excelReport"] as Stream;
return new FileStreamResult(ExcelReport, "application/ms-excel")
{
FileDownloadName = "Report" + DateTime.Now.ToString("MMMM d, yyy") + ".xls"
};
}
I've debugged through the AdminEngine, and everything looks fine. However, in the ExcelReport action, when it comes to returning the file - it doesn't. What I see is a lot of characters on screen (in the 'panelReport' div - see below), mixed in with what would be the data in the excel file.
I think I have established that the reason it is being displayed on screen is as a result of some code
that was written in the Index view:
<% using (Ajax.BeginForm("ProductReport", "Report", null,
new AjaxOptions
{
UpdateTargetId = "panelReport",
InsertionMode = InsertionMode.Replace,
OnSuccess = "pageLoaded",
OnBegin = "pageLoading",
OnFailure = "pageFailed",
LoadingElementId = ""
},
new { id = "SearchForm" })) %>
As you can see, the Ajax.BeginForm statement states that it should update to the panelReport div - which is what it's doing (through the Product Report partial view). While this is perfect for when the reports need to be displayed on screen, it is obviously not going to work with an excel file.
Is there a way of working around this issue without changing the existing code too much?
Here is the class where I do the workings for the excel file in case it's required to shed light on the situation:
Report Class:
public Stream GetExcelAdminReport(AdminReportRequest reportRequest)
{
AdminReport report = new AdminReport();
string dateRange = null;
List<ProductSale> productSales = GetSortedListOfProducts(reportRequest, out dateRange);
report.DateRange = dateRange;
if (productSales.Count > 0)
{
report.HasData = true;
CustomisedSalesReport CustSalesRep = new CustomisedSalesReport();
Stream SalesReport = CustSalesRep.GenerateCustomisedSalesFile(productSales);
return SalesReport;
}
}
Workings Class:
public class CustomisedSalesReport
{
public Stream GenerateCustomisedSalesFile(List<ProductSale> productSales)
{
MemoryStream ms = new MemoryStream();
HSSFWorkbook templateWorkbook = new HSSFWorkbook();
HSSFSheet sheet = templateWorkbook.CreateSheet("Sales Report");
//Workings
templateWorkbook.Write(ms);
ms.Position = 0;
return ms;
}
}
The problem is pretty obvious that you are using an Ajax Form to download a file. On top you are using the built-in Microsoft Ajax libraries, which seem to be not intelligent enough.
I can provide 2 solutions:
The easiest solution (which I have used in the past) is that instead of streaming a file yourself, create an excel file and save it on the server and then send the download link to the user. It won't require a lot of change to the code.
You could handle the OnSubmit event of the AjaxForm, see if you it's a file to download. If yes, then make a full postback request (using $.post()). This way the browser will automatically pop-up the dialog asking for where to download.
Hope it makes sense.

manually updating database table values are not reflecting in webpage - aspnet mvc

i noticed some wierd problem i.e i have built a web page on which information comes from database table named "school", when i change some data in that table manually from mssql the web page data is still same as previous, its not gettin' changed, i dn't know how it is possible.
this is my action controller
public ActionResult SchoolDetails(string id,_ASI_School schoolDetails)
{
schoolDetails = SchoolRepository.GetSchoolById(id);
return View(schoolDetails);
}
This is my view
=Html.Encode(Model.SchoolName)
= Html.Encode(Model.SchoolAddress)
= Html.Encode(Model.SchoolEmail)
code for GetSchoolById()..
private static ASIDataContext db = new ASIDataContext();
public static _ASI_School GetSchoolById(string schoolId)
{
return db._ASI_Schools.SingleOrDefault(x => x.SchoolId == schoolId);
}
try putting this above your SchoolDetails ActionResult
[OutputCache( Duration=0)]
MVC does some really nice server side caching as well that clearing the cache on the browser does not fix.

Categories

Resources