How to get a build date for an ASP.NET application? - asp.net

Jeff wrote about getting a file version/datestamp a while back. Visual studio doesn't increment builds unless you close/reopen the solution, so grabbing the timestamp seems to be the best way to verify what build you are using.
I ported the solution to C#
// from http://www.codinghorror.com/blog/archives/000264.html
protected DateTime getLinkerTimeStamp(string filepath){
const int peHeaderOffset = 60;
const int linkerTimestampOffset = 8;
byte[] b = new byte[2048];
Stream s = null;
try {
s = new FileStream(filepath, FileMode.Open, FileAccess.Read);
s.Read(b, 0, 2048);
}
finally{
if (s != null){
s.Close();
}
}
int i = BitConverter.ToInt32(b, peHeaderOffset);
int secondsSince1970 = BitConverter.ToInt32(b, i + linkerTimestampOffset);
DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0);
dt = dt.AddSeconds(secondsSince1970);
dt = dt.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours);
return dt;
}
protected DateTime getBuildTime()
{
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
return getLinkerTimeStamp(assembly.Location);
}
Which seems to work. Is there a better / more official way to tell when a site was deployed?

I think your easiest route is to have a timestamp in your web.config.
There are really two ways you can update this in your web.config. The first is to use an automated build tool such as NAnt. It gives you the option of modifying the web.config like you would want. This is the method I use.
Another option available to you if you don't use an automated build tool is to add code in your pre-build event in Visual Studio to update the web.config for you. Here is an article on Codeplex which should get you started.
http://www.codeproject.com/KB/dotnet/configmanager_net.aspx

Related

Error message "entries cannot be opened multiple times in update mode." in Spreadsheet Lite SaveAs function

Upon execution of the dBWorksheet.SaveAs(xlsFileSpec), in the code below, I am seeing an exception:
"entries cannot be opened multiple times in update mode."
SLDocument dBWorksheet = new SLDocument();
TimeSpan interval = new TimeSpan(0, 0, 2);
dBWorksheet.SetCellValue(2, 1, "Hour");
dBWorksheet.SetCellValue(3, 1, "Time");
int Row = 3;
// Create the hour and time of day columns.
for(TimeSpan dBTime = new TimeSpan(0, 0, 0); dBTime.TotalHours < 24; dBTime = dBTime.Add(interval))
{
dBWorksheet.SetCellValue(Row, 1, dBTime.Hours);
dBWorksheet.SetCellValue(Row, 2, dBTime.ToString());
Row++;
}
// Save the new worksheet.
dBWorksheet.SaveAs(xlsFileSpec);
I had this error when I opened (by SpreadsheetLight) .xlsx file that was saved (by LibreOffice Calc) in "Excel 2007-365" format and then I tried use a SaveAs function.
When I save (by LibreOffice Calc) the .xlsx file as "Office Open XML" then I can Open and SaveAs (by SpreadsheetLight) a .xlsx file without problems.
Here's how I solved it.
Downloaded the source code for SpreadsheetLight (version 3.5).
http://spreadsheetlight.com/downloads/SpreadsheetLight3.5.zip
Created a .NET Core library project with the name "SpreadsheetLight" and added necessary NuGet packages (DocumentFormat.OpenXML and System.Drawing.Common) to it. Copied and pasted all the downloaded source code files in this project.
Added the project "SpreadsheetLight" to my solution and referenced it in one of the existing projects.
In "SLDocument.cs" file, make the following changes in the method "LoadDocumentProperties()" so that the code looks like the following:
// XDocument xdoc = XDocument.Load(XmlReader.Create(xl.CoreFilePropertiesPart.GetStream()));
Stream stream = xl.CoreFilePropertiesPart.GetStream();
XDocument xdoc = XDocument.Load(XmlReader.Create(stream));
foreach (XElement xelem in xdoc.Descendants())
{
// Code omitted.
}
stream.Close();
Build your solution and test it.
Roll-back from .NET Core 3.0 to .NET Framework 4.7.x
This is obviously not the most desirable solution.
However, the only solution that I have found is to roll-back the application from .NET Core 3.0 and SpreadsheetLight.Core to .NET Framework 4.7.x and SpreadsheetLight.
The code posted in the question above runs without modification.
I believe this has to do with a memory leak that was fixed in System.IO.Packaging in .NET Core 3.0. This will require further investigation and probably a fix to SpreadsheetLight.Core.
A bit late to the party but just bumped in to this problem.
I solved this by create a new SLDocument and copied cell by cell from the old SLDocument. Might not work 100%, but it has covered my reports so far.
Code
using (var file = new SLDocument())
{
file.CopyFromTemplate(Path.Combine("ReportTemplates\\Tackningsbidrag_budget.xlsx"), maxCols: 20, maxRows: 10);
// code
using (var ms = new MemoryStream())
{
file.SaveAs(ms);
}
}
Extension method:
public static void CopyFromTemplate(this SLDocument file, string pathToOrgFile, int? maxCols = null, int? maxRows = null)
{
using (var orgFile = new SLDocument(pathToOrgFile))
{
var page = orgFile.GetPageSettings();
file.SetPageSettings(page);
foreach (var cell in orgFile.GetWorksheetMergeCells())
{
file.MergeWorksheetCells(cell.StartRowIndex, cell.StartColumnIndex, cell.EndRowIndex, cell.EndColumnIndex);
}
var stats = orgFile.GetWorksheetStatistics();
var endCol = stats.EndColumnIndex;
if (maxCols.HasValue && maxCols < endCol)
{
endCol = maxCols.Value;
}
var endRow = stats.EndRowIndex;
if (maxRows.HasValue && maxRows < endRow)
{
endRow = maxRows.Value;
}
for (int col = stats.StartColumnIndex; col <= endCol; col++)
{
file.SetColumnStyle(col, orgFile.GetColumnStyle(col));
file.SetColumnWidth(col, orgFile.GetColumnWidth(col));
}
for (int row = stats.StartRowIndex; row <= endRow; row++)
{
file.SetRowStyle(row, orgFile.GetRowStyle(row));
file.SetRowHeight(row, orgFile.GetRowHeight(row));
}
for (int row = stats.StartRowIndex; row <= endRow; row++)
{
for (int col = stats.StartColumnIndex; col <= endCol; col++)
{
var formula = orgFile.GetCellFormula(row, col);
var stringValue = orgFile.GetCellValueAsString(row, col);
file.SetCellValue(row, col, !string.IsNullOrWhiteSpace(formula) ? ("=" + formula) : stringValue);
file.SetCellStyle(row, col, orgFile.GetCellStyle(row, col));
}
}
}
}

Render image in asp.net MVC

My scenario is this:
I create o custom report based on a stored procedure that returns three columns (person_id[long], name[varchar(100)], age[int], photo[image]). Those are the columns and types in my database table.
Right now i'm using something like this for each image of the report.
<img src="<%= Url.Action("ShowImage", "Reports", new {personId = result["PERSON_ID"]}) %>" />
with ShowImage being
public virtual ActionResult ShowImage(long? personId)
{
try
{
if (personId.HasValue)
{
byte[] imageArray = StudentClient.GetPersonPhotoById(personId.Value);
if (imageArray == null)
return File(noPhotoArray, "image/jpg");
#region Validate that the uploaded picture is an image - temporary code
// Get Mime Type
byte[] buffer = new byte[256];
buffer = imageArray.Take(imageArray.Length >= 256 ? 256 : imageArray.Length).ToArray();
var mimeType = UrlmonMimeType.GetMimeType(buffer);
if (String.IsNullOrEmpty(mimeType) || mimeType.IndexOf("image") == -1)
return File(noPhotoArray, "image/jpg");
#endregion
return File(imageArray, "image/jpg");
}
}
catch
{
return File(noPhotoArray, "image/jpg");
}
}
I would like to use some sort of alternative because this is very stresful due to the fact the ShowImage() calls a service method StudentClient.GetPersonPhotoById(personId.Value); for every single picture, meaning allot of calls to the service and the DB also.
I would like to actually use that photo column that returns a byte array instead of using the Person_id column through the ShowImage controller method.
That would practicaly reduce the number of calls to the service to 0 and use the actual data from the image column. This seems pretty straight forward but I struggle to find a solution.
Thank you!
Simplest solution - use OutputCache. Moreover, you can set cache location to client, and the browser will cache the images once they're downloaded. VaryByParam will give you the ability to cache images depending on personId.
There's quite a neat technique where you can stream the binary data directly from the SQL Server to the client, via the webserver.
This is my code for doing it:
public void StreamFile(Stream stream)
{
DbDataReader dr = LoadDbStream();
if (!dr.Read())
return;
const int BUFFERSIZE = 512;
byte[] Buffer = new byte[BUFFERSIZE];
long StartIndex = 0;
long Read = dr.GetBytes(0, StartIndex, Buffer, 0, BUFFERSIZE);
while (Read == BUFFERSIZE)
{
stream.Write(Buffer, 0, BUFFERSIZE);
StartIndex += BUFFERSIZE;
Read = dr.GetBytes(0, StartIndex, Buffer, 0, BUFFERSIZE);
}
stream.Write(Buffer, 0, (int)Read);
}
private DbDataReader LoadDbStream()
{
DbCommand cmd = Cms.Data.GetCommand("SELECT Data FROM CMS_Files WHERE FileId = #FileId", "#FileId", Id.ToString());
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection.Open();
return cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection);
}
The command object is an ordinary command object. The key part is the CommandBehavior.SequentialAccess flag as this makes sql server only send data when you ask for. You therefore can only read the columns in the order they are specified in the query. the other point to make is stream should be the outputstream from the request & switch output buffering off.
Couple this with outputcaching and you reduce the memory load on the server.
Simon
You can use this as source form the image.
src="data:image/jpg;base64,<%= System.Convert.ToBase64String(result["PHOTO"] as byte[]) %>"

how to get the image dimesion without using bitmap or graphics object in .net

i want to create SQL CLR integrated function from Visual C#, now my requirement is user will pass a folder path as a paramter, and the function should get all the image file from the the folder, and get its basic property like FileSize, dimension etc.. but it seems SQL project does not supports System.Drawing Namespace... as i created the same function in normal project it worked fine, as i was able to use System.Drawing Namespace, but here i cannot use, System.Drawing Namespace.. so is there any other way to get the image dimension...
below is the code i have used in my normal project.
public DataTable InsertFile(string FolderPath)
{
DataTable dt = new DataTable();
DataColumn[] col = new DataColumn[] { new DataColumn("FileName", typeof(System.String)), new DataColumn("FileSize", typeof(System.Int32)), new DataColumn("FilePath", typeof(System.String)), new DataColumn("Width", typeof(System.Int32)), new DataColumn("Height", typeof(System.Int32)) };
dt.Columns.AddRange(col);
FileInfo info= null;
Bitmap bmp = null;
foreach (String s in Directory.GetFiles(FolderPath, "*.jpg"))
{
info = new FileInfo(s);
bmp = new Bitmap(s);
DataRow dr = dt.NewRow();
dr["FileName"] = Path.GetFileName(s);
dr["FileSize"] = info.Length / 1024;
dr["FilePath"] = s;
dr["Width"] = bmp.Width;
dr["Height"] = bmp.Height;
dt.Rows.Add(dr);
}
return dt;
}
does anyone have any idea how to get image dimension without using System.Drawing Namespace.
wow never seen anyone try this before, but if using Drawing in a SQL project isn't allowed try reading the header info like this http://www.codeproject.com/KB/cs/ReadingImageHeaders.aspx
Edit included the code, with the change to remove the dependency on Size.
while (binaryReader.ReadByte() == 0xff)
{
byte marker = binaryReader.ReadByte();
ushort chunkLength = binaryReader.ReadLittleEndianInt16();
if (marker == 0xc0)
{
binaryReader.ReadByte();
int height = binaryReader.ReadLittleEndianInt16();
int width = binaryReader.ReadLittleEndianInt16();
return new int[] { width, height };
}
binaryReader.ReadBytes(chunkLength - 2);
}
Is the Image object any better for you?
System.Drawing.Image forSize = System.Drawing.Image.FromFile(s);
dr["Width"] = forSize.Width;
and so forth.
That any better or same problem?

Need to find the length of audio file in minutes in asp.net

I have asp.net application in which i am uploading audio files by converting them into the stream and upload to the database.But not able to find the length of the audio file into minutes.Here problem is that my asp.net application is present in the cloud.For uploading i am using upload file control of asp.net.Please suggest solution for this.
You may look at taglib#
I would have expected that you can calculate this from the bit rate and the file length: (file.lenghtInBits / kbsp ) / 60 = minutes.
rather assumes that you can get the bit rate from the file header though.
You will need to reference Windows Media Player. Go to Com Add-ins to add the wmp.dll to your project.
string Duration = null;
WMPLib.WindowsMediaPlayer w = new WMPLib.WindowsMediaPlayer();
WMPLib.IWMPMedia mediaFile = w.newMedia(Filename);
if (mediaFile != null) {
Duration = mediaFile.durationString;
}
w.close();
You could use the NAudio library as suggested in this answer to a similar SO question.
We can do it easily by given below code
private string GetDuration(string FileFullPath)
{
string duration = "";
string fName = FileFullPath.Substring(FileFullPath.LastIndexOf("\\") + 1);
string filePath = FileFullPath.Substring(0, FileFullPath.LastIndexOf("\\"));
Shell32.Shell shell = new Shell32.ShellClass();
Shell32.Folder folder = shell.NameSpace(filePath);
Shell32.FolderItem folderItem = folder.ParseName(fName);
if (folderItem != null)
{
duration = folder.GetDetailsOf(folderItem, 21);
}
folderItem = null;
folder = null;
shell = null;
return duration;
}
TimeSpan span= GetWavFileDuration(filePath + "\" + fileName);
string spanSeconds = span.TotalSeconds.ToString();
string[] spanSecondsArray=spanSeconds.Split('.');
spanSeconds = spanSecondsArray[0].ToString();
public static TimeSpan GetWavFileDuration(string fileName) {
WaveFileReader wf = new WaveFileReader(fileName);
return wf.TotalTime;
}
You can use this library for getting the Audio file duration

ASP.NET Backgroundworkers for spreadsheet creation: multiple ones interfering with each other?

I am writing an ASP.NET application in which i need to create multiple excel reports. the report creation is pretty time-consuming (up to ten seconds for each) so i am using backgroundworkers to create them simultaneously.
My code looks a bit like this:
if (condition1)
{
excel_file_name = "TRANSFER";
BackgroundWorker worker_t = new BackgroundWorker();
worker_t.DoWork += new DoWorkEventHandler(DoWork);
worker_t.WorkerReportsProgress = false;
worker_t.WorkerSupportsCancellation = true;
worker_t.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(WorkerCompleted);
worker_t.RunWorkerAsync(excel_file_name);
}
if (Condition2)
{
excel_file_name = "NEFT";
BackgroundWorker worker_n = new BackgroundWorker();
worker_n.DoWork += new DoWorkEventHandler(DoWork);
worker_n.WorkerReportsProgress = false;
worker_n.WorkerSupportsCancellation = true;
worker_n.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(WorkerCompleted);
worker_n.RunWorkerAsync(excel_file_name);
}
there are more conditions but i haven't written them, since they are all similar. the only difference is the Excel_File_Name
the DoWork even then calls a class to create the excel files with the given name.
When condition1 and condition2 are both true, Here is the issue:
1. if i run this slowly using breakpoints during debugging, both files (TRANSFER and NEFT) are created.
2. if, however, i run it without breakpoints like a normal application, only the last file (NEFT in this example) is created.
What can be the issue?
Thanks
PS: For further information, here is the important code from the class that creates the excel file:
private static string placeDataInTemplate(string destFilePath, DataRow dr, bool isCoverLetter)
{
int loop = 0;
ExcelNamespace.Application excelApplication = new ExcelNamespace.Application();
ExcelNamespace.Workbook workbook = excelApplication.Workbooks.Open(destFilePath, 0, false, 5,
"", "", true, ExcelNamespace.XlPlatform.xlWindows, "\t", false, false, 0, true, true, false);
ExcelNamespace.Worksheet workSheet = (ExcelNamespace.Worksheet)workbook.Sheets[sheet_no];
try
{
string value;
string replicate;
string replicate_end;
// get data for Place Holders
sDataTable dtPlaceHolderData = getPlaceHolderData(dr);
//make Display Alerts False
excelApplication.DisplayAlerts = false;
if (dtPlaceHolderData != null && dtPlaceHolderData.Rows.Count > 0)
{
int rowCntDt = 0; //Which row will be used for data?
int i = 1;
Excel.Range Find = (ExcelNamespace.Range)workSheet.Cells.Find("#",
(ExcelNamespace.Range)workSheet.Cells[1, 1],
Excel.XlFindLookIn.xlValues,
Excel.XlLookAt.xlPart,
Excel.XlSearchOrder.xlByRows,
Excel.XlSearchDirection.xlNext,
false,
false,
Missing.Value);
while (Find != null && loop <= 200)
{
loop++;
value = Find.Value2.ToString();
if (condition)
//VERY long if...else if
}
string approveDirPath = destFilePath.Replace(Path.GetFileName(destFilePath), string.Empty);
workbook.Close(true, destFilePath, Type.Missing);
excelApplication.Quit();
string filepath = destFilePath.Split('-')[0];
string approval_id = dr[0].ToString();
return destFilePath;
}
return string.Empty;
}
catch (Exception ex)
{
//do something
}
finally
{
//release resources
}
NOTE: I have removed a lot of needless code. I can paste it if needed. Thank you
Most likely cause is some shared state between two threads - shared state may include excel application and workbooks. So you need to inspect your code for the same.
On the side note, instead of using Excel Automation to generate excel files, you may consider using some in-process library which would be perhaps more scalable and void of such issues. Have a look at one such free basic library at code project

Resources