Render image in asp.net MVC - asp.net

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[]) %>"

Related

Application Cache and Slow Process

I want to create an application wide feed on my ASP.net 3.5 web site using the application cache. The data that I am using to populate the cache is slow to obtain, maybe up to 10 seconds (from a remote server's data feed). My question/confusion is, what is the best way to structure the cache management.
private const string CacheKey = "MyCachedString";
private static string lockString = "";
public string GetCachedString()
{
string data = (string)Cache[CacheKey];
string newData = "";
if (data == null)
{
// A - Should this method call go here?
newData = SlowResourceMethod();
lock (lockString)
{
data = (string)Cache[CacheKey];
if (data != null)
{
return data;
}
// B - Or here, within the lock?
newData = SlowResourceMethod();
Cache[CacheKey] = data = newData;
}
}
return data;
}
The actual method would be presented by and HttpHandler (.ashx).
If I collect the data at point 'A', I keep the lock time short, but might end up calling the external resource many times (from web pages all trying to reference the feed). If I put it at point 'B', the lock time will be long, which I am assuming is a bad thing.
What is the best approach, or is there a better pattern that I could use?
Any advice would be appreciated.
I add the comments on the code.
private const string CacheKey = "MyCachedString";
private static readonly object syncLock = new object();
public string GetCachedString()
{
string data = (string)Cache[CacheKey];
string newData = "";
// start to check if you have it on cache
if (data == null)
{
// A - Should this method call go here?
// absolut not here
// newData = SlowResourceMethod();
// we are now here and wait for someone else to make it or not
lock (syncLock)
{
// now lets see if some one else make it...
data = (string)Cache[CacheKey];
// we have it, send it
if (data != null)
{
return data;
}
// not have it, now is the time to look for it.
// B - Or here, within the lock?
newData = SlowResourceMethod();
// set it on cache
Cache[CacheKey] = data = newData;
}
}
return data;
}
Better for me is to use mutex and lock depended on the name CacheKey and not lock all resource and the non relative one. With mutex one basic simple example will be:
private const string CacheKey = "MyCachedString";
public string GetCachedString()
{
string data = (string)Cache[CacheKey];
string newData = "";
// start to check if you have it on cache
if (data == null)
{
// lock it base on resource key
// (note that not all chars are valid for name)
var mut = new Mutex(true, CacheKey);
try
{
// Wait until it is safe to enter.
// but also add 30 seconds max
mut.WaitOne(30000);
// now lets see if some one else make it...
data = (string)Cache[CacheKey];
// we have it, send it
if (data != null)
{
return data;
}
// not have it, now is the time to look for it.
// B - Or here, within the lock?
newData = SlowResourceMethod();
// set it on cache
Cache[CacheKey] = data = newData;
}
finally
{
// Release the Mutex.
mut.ReleaseMutex();
}
}
return data;
}
You can also read
Image caching issue by using files in ASP.NET

Encrypted mp3 streaming to Flash SWF

I have an asp.net web site that serves sample MP3 files to client Flash Players (SWF).
These files are downloadable by tons of download tools.
Although only registered members can access the high quality mp3 samples, my client wants to prevent these low quality MP3 files to be downloaded by download tools.
So I thought about this solution:
Convert these MP3 files to bytearrays on server side (ASP.NET)
Do some bitwise XOR operations (Simple encryption)
Write this array to aspx' responsestream
Modify Flash (.fla) to request to this new file/page/aspx
Do some bitwise XOR operations on Flash and convert it to the original MP3 as byte array. (Simple decryption)
Play the MP3
I was able to succeed till step 6. I cannot convert this byte array to a Sound object that Flash can play. I did a bit by bit comparison of the resulting array on the flash and the source array on ASP.NET. They are equal.
I'm open to completely different approaches. But I cannot use Flash Media Server. I need to be using Flash as3 and ASP.NET.
Also very important! The .mp3 must be downloaded/decrypted and played asynchronously (which I coud not succeed in doing)
I agree with Peter Elliot that authentication probably is the easiest way to restrict access to the files. However, if you still need to explore the route of encrypting the files, I thought I'd expand a bit on Alex Vlad's answer.
What you need to do in order to be able to stream the audio file, decrypt it on the fly, and play it asynchronously is to use the URLStream class (docs) in conjunction with the Sound class (docs) and keeping a buffer of the partially downloaded content.
Some pseudocode to illustrate:
class AsyncEncryptedSoundPlayer extends Sound {
var buffer:ByteArray;
var stream:URLStream;
var currSoundPosition:uint = 0;
public function AsyncEncryptedSoundPlayer(url:String) {
buffer = new ByteArray();
stream = new URLStream();
stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
stream.load(new URLRequest(url));
addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataRequested);
}
function onProgress(e:ProgressEvent):void {
var tmpData:ByteArray;
stream.readBytes(tmpData, buffer.length, stream.bytesAvailable - buffer.length);
var decryptedData:ByteArray = decryptData(tmpData); // Decrypt loaded data
buffer.writeBytes(decryptedData, buffer.length, decryptedData.length); // Add decrypted data to buffer
}
function onSampleDataRequested(e:ProgressEvent):void {
// Feed samples from the buffer to the Sound instance
// You may have to pause the audio to increase the buffer it the download speed isn't high enough
event.data.writeBytes(buffer, currSoundPosition, 2048);
currSoundPosition += 2048;
}
function decryptedData(data:ByteArray):void {
// Returns decrypted data
}
}
This is obviously a very rough outline of a class, but I hope it will point you in the right direction.
#walkietokyo, thanks a lot for pointing me to the right direction. I succeeded in doing what I wanted. The keyword here was the loadCompressedDataFromByteArray function.
After tens of trial and errors I found out that loadCompressedDataFromByteArray was working in a differential manner.
It appends anything that it converts to the end of the sound object data.
Another issue: sound object doesn't continue playing the parts appended by loadCompressedDataFromByteArray after its play function is called.
So I implemented a sort of double buffering. Where I use 2 sound objects interchangeably.
My final (test) version is listed below. With the encryption (obfuscation) method I used (a simple XOR) no download manager or grabber or sniffer that I tested was able to play the Mp3s.
Flash (Client) side:
import flash.events.DataEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.OutputProgressEvent;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.net.URLStream;
import flash.utils.ByteArray;
import flashx.textLayout.formats.Float;
var buffer:ByteArray;
var stream:URLStream;
var bufferReadPosition:uint = 0;
var bufferWritePosition:uint = 0;
var url:String = "http://www.blablabla.com/MusicServer.aspx?" + (new Date());
buffer = new ByteArray();
stream = new URLStream();
stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
stream.load(new URLRequest(url));
var s1:Sound = new Sound();
var s2:Sound = new Sound();
var channel1:SoundChannel;
var channel2:SoundChannel;
var pausePosition:int = 0;
var aSoundIsPlaying:Boolean = false;
var lastLoadedS1:Boolean = false;
var lastS1Length:int = 0;
var lastS2Length:int = 0;
function onProgress(e:ProgressEvent):void {
var tmpData:ByteArray = new ByteArray();
stream.readBytes(tmpData, 0, stream.bytesAvailable);
var decryptedData:ByteArray = decryptData(tmpData); // Decrypt loaded data
buffer.position = bufferWritePosition;
buffer.writeBytes(decryptedData, 0, decryptedData.length); // Add decrypted data to buffer
bufferWritePosition += decryptedData.length;
if(lastLoadedS1)
{
buffer.position = lastS2Length;
s2.loadCompressedDataFromByteArray(buffer, buffer.length - lastS2Length);
lastS2Length = buffer.length;
}
else
{
buffer.position = lastS1Length;
s1.loadCompressedDataFromByteArray(buffer, buffer.length - lastS1Length);
lastS1Length = buffer.length;
}
if(!aSoundIsPlaying)
{
DecidePlay();
}
}
function channel1Completed(e:Event):void
{
DecidePlay();
}
function channel2Completed(e:Event):void
{
DecidePlay();
}
function DecidePlay():void
{
aSoundIsPlaying = false;
if(lastLoadedS1)
{
channel1.stop();
if(s2.length - s1.length > 10000)
{
//At least a 10 second buffer
channel2 = s2.play(s1.length);
channel2.addEventListener(Event.SOUND_COMPLETE, channel2Completed);
lastLoadedS1 = false;
aSoundIsPlaying = true;
}
}
else
{
if(channel2 != null)
{
channel2.stop();
}
if(s1.length - s2.length > 10000)
{
//At least a 10 second buffer
channel1 = s1.play(s2.length);
channel1.addEventListener(Event.SOUND_COMPLETE, channel1Completed);
lastLoadedS1 = true;
aSoundIsPlaying = true;
}
}
}
function decryptData(data:ByteArray):ByteArray {
for(var i:int = 0;i<data.length;i++)
{
//Here put in your bitwise decryption code
}
return data;
}
ASP.NET server side (MusicServer.aspx):
protected void Page_Load(object sender, EventArgs e)
{
CopyStream(Mp3ToStream(Server.MapPath("blabla.mp3")), Response.OutputStream);
this.Response.AddHeader("Content-Disposition", "blabla.mp3");
this.Response.ContentType = "audio/mpeg";
this.Response.End();
}
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
for (int i = 0; i < read; i++)
{
//Here put in your bitwise encryption code
}
output.Write(buffer, 0, read);
}
}
public Stream Mp3ToStream(string filePath)
{
using (FileStream fileStream = File.OpenRead(filePath))
{
MemoryStream memStream = new MemoryStream();
memStream.SetLength(fileStream.Length);
fileStream.Read(memStream.GetBuffer(), 0, (int)fileStream.Length);
return memStream;
}
}
what might be simpler than encrypting the data coming back from your service is instead authenticating requests so that only your swf can request the files.
You can accomplish this in the same way that say, the Amazon APIs work: build a request that includes a number of parameters, including a timestamp. hash all of these arguments together in an HMAC (HMAC-SHA256 is available in the as3crypto library) along with a private key embedded in your swf. Your server end authenticates this request, ensuring that the hash is valid and that it is close enough to the timestamp. Any requests with a bad hash, or using a request with a timestamp too far in the past (replay attack) are denied.
This is certainly not perfect security. Any sufficiently motivated user could disassemble your swf and pull out your auth key, or grab the mp3 from their browser cache. But then again, any mechanism you are going to use will have those issues. This removes the overhead of having to encrypt and decrypt all of your files, instead moving the work over to the request generation phase.
Flash Sound supports only streaming mp3 playing that is you can play only mp3 by direct link. But you can send swf file with embeded mp3 withing it and this swf can be encrypted in the same way as you encrypt mp3.
as3 code for embedding and using mp3:
public class Sounds
{
[Embed(source="/../assets/sounds/sound1.mp3")]
private static const sound1:Class;
}
after loading this swf by the Loader you can access to the sound in this way:
var domain:ApplicationDomain = ApplicationDomain.currentDomain; // <-- ApplicationDomain where you load sounds.swf
var soundClass:Class = domain.getDefinition("Sounds_sound1");
var sound:Sound = new soundClass();
sound.play();
Be sure, that you do at least one of the follows:
give different names for sound class (sound1)
give different name for holder class (Sounds)
or load sound.swf into different application domains
to prevent class names overlapping.
Unfortunate this approach doesn't allow you to streaming play sound, you have to load whole swf, decrypt it and only after that you will be able to play sound.
please have a look here:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/SampleDataEvent.html
and here:
http://help.adobe.com/en_US/as3/dev/WSE523B839-C626-4983-B9C0-07CF1A087ED7.html

how can we store a html page into sqlite in blackberry on memory card / phone memory?

Below code specifies that we we can make http connection in blackberry and how to store html page as a string?
I am doing this but I am able to get that http request but when I get response i.e http_ok it is not correct so that I can save text oh html as a string and I can further store that into sqlite.
LabelField title = new LabelField("SQLite Create Database Sample",
LabelField.ELLIPSIS |
LabelField.USE_ALL_WIDTH);
setTitle(title);
add(new RichTextField("Creating a database."));
argURL="https://www.google.com:80";
try {
connDesc = connFact.getConnection(argURL);
if (connDesc != null) {
httpConn = (HttpConnection) connDesc.getConnection();
// //Send Data on this connection
// httpConn.setRequestMethod(HttpConnection.GET);
// //Server Response
StringBuffer strBuffer = new StringBuffer();
inStream = httpConn.openInputStream();
int chr;
int retResponseCode = httpConn.getResponseCode();
if (retResponseCode == HttpConnection.HTTP_OK) {
if (inStream != null) {
while ((chr = inStream.read()) != -1) {
strBuffer.append((char) chr);
}
serverResponceStr = strBuffer.toString();
// appLe.alertForms.get_userWaitAlertForm().append("\n"+serverResponceStr);
//returnCode = gprsConstants.retCodeSuccess;
}
} else {
//returnCode = gprsConstants.retCodeNOK;
}
}
} catch (Exception excp) {
//returnCode = gprsConstants.retCodeDisconn;
excp.printStackTrace();
} `enter code here`
The code does not perform any database functionality, however I tested and it does successfully perform an HttpRequest to an external URL. The data that comes back is based on the response of the server you are making the request to.
The code I used can be found here:
http://snipt.org/vrl7
The only modifications is to keep a running summary of various events, and the response is displayed in the RichTextField. Basically, this looks to be working as intended, and the resulting String should be able to be saved however you see fit; though you may need to be cautious of encoding when saving to a database so that special characters are not lost or misinterpreted.

Out Of Memory exception if files to big

I'm currently working on a data-check for images. I need to request the Size (width & height) and the resolution of the image. Files over 70MB throw an "out of memory" exception on GDI Problem. Is there an alternative way to get the file-information? The same error on parse it through FromStream...
Using myfile = Image.FromFile(filePath)
...
End Using
You can use the following code to get image properties (it loads metadata only):
using (var fs = new FileStream(#"C:\Users\Dmitry\Pictures\blue-earth-wallpaper.jpg", FileMode.Open, FileAccess.Read)) {
var decoder = BitmapDecoder.Create(fs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
var size = decoder.Frames[0].PixelWidth;
var height = decoder.Frames[0].PixelHeight;
var dpiX = decoder.Frames[0].DpiX;
var dpiY = decoder.Frames[0].DpiY;
}
I found this link http://www.fastgraph.com/help/image_file_header_formats.html that tells where in the file you can find the type and its dimensions. I guess, if you use something like this below to seek and get the first few bytes and close once you are done, shouldnt be using much resources
Untested code below...
// This really needs to be a member-level variable;
private static readonly object fsLock = new object();
// Instantiate this in a static constructor or initialize() method
private static FileStream fs = new FileStream("myFile.txt", FileMode.Open);
public string ReadFile(int fileOffset) {
byte[] buffer = new byte[bufferSize];
int arrayOffset = 0;
lock (fsLock) {
fs.Seek(fileOffset, SeekOrigin.Begin);
int numBytesRead = fs.Read(bytes, arrayOffset , bufferSize);
// Typically used if you're in a loop, reading blocks at a time
arrayOffset += numBytesRead;
}
// Do what you want to the byte array and close
}

How could I insert a string into the response stream anywhere I want?

There may be an easy way to do this but I can't see it...
I created a simple Http Module that starts a timer on the PreRequestHandler and stops the timer on the PostRequestHandler to calculate the time it took the page to load.
I then create some simple html and write my results to Response.Write. Since I'm doing this in the PostRequestHandler it's adding my results after the </html> tag. That's fine for testing but I need in a scenario where the page needs to validate.
I can't seem to figure out how I could manipulate the Response object to insert my results before the </body> tag. Response.Write and Response.Output.Write don't have that flexibility and I couldn't see a way to work with the Response as a string. Am I missing something easy?
To do this, you'd have to implement your own stream object and use that as a filter for your response.
For isntance:
public class TimerStream : Stream
{
private Stream inner { get; set; }
private StringBuilder responseHtml;
public TimerStream(Stream inputStream) {
inner = inputStream;
responseHtml = new StringBuilder();
// Setup your timer
}
/* Filter overrides should pass through to inner, all but Write */
public override void Write(byte[] buffer, int offset, int count)
{
string bufferedHtml = System.Text.UTF8Encoding.UTF8.GetString (buffer, offset, count);
Regex endTag = new Regex ("</html>", RegexOptions.IgnoreCase);
if (!endTag.IsMatch (bufferedHtml))
{
responseHtml.Append(bufferedHtml);
}
else
{
// insert timer html into buffer, then...
responseHtml.Append (bufferedHtml);
byte[] data = System.Text.UTF8Encoding.UTF8.GetBytes (responseHtml.ToString ());
inner.Write (data, 0, data.Length);
}
}
}
Then, in your HttpModule, you'd add this to your BeginRequest:
// Change the Stream filter
HttpResponse response = context.Response;
response.Filter = new TimerStream(context.Response.Filter);

Resources