views:

58

answers:

4

I want to display photo of employee who is login but our company doesn't want to expose the photos of all employees publically that is why we put that employees photos on a server that is not live but connected with the live server.

Now problem it that when I run my website on localhost the photos of employees display but as soon as I publish it on IIS it doesn't display images.

Please suggest a solution.

+1  A: 

More than likely, the client doesn't have access to the server where the images are. The image is downloaded by the client from the image server. It is not downloaded from the IIS server.

Take a look at the page source and look for the src attribute of the image. You'd need to proxy the request from the client through a public IIS server to the internal server to get the image back to the client. Of course, without authentication, you'd be defeating the original purpose of putting the images on an internal server.

Paul Kearney - pk
A: 

Presumably, your intranet is set up so that your public-facing web server can "see" the server on which the photos reside, but the photo server itself is not public-facing. The web site contains links to the photos on the photo server, but since that server is not public-facing the photos do not show up (except when run on localhost, which can see the photo server).

This code snippet shows the basics of one way to do this in .NET:

protected void Page_Load(object sender, EventArgs e)
{
    HttpContext.Current.Response.Clear();
    HttpContext.Current.Response.ContentType = "image/jpeg";
    using (Bitmap bmp = 
        (Bitmap)Bitmap.FromFile(
            @"\\internal-photoserver\shared drive\bobsmith.jpg"))
    {
        bmp.Save(
            HttpContext.Current.Response.OutputStream,
            ImageFormat.Jpeg);
    }
    HttpContext.Current.Response.End();
}
// needs these two using statements:
using System.Drawing;
using System.Drawing.Imaging;

Basically, instead of rendering the page with a link to the image file, the server instead reads the file and streams it to the client along with the rest of the page (so the browser never needs to access the photo server). As long as the web server can see "internal-photoserver", this code will work and display the photo in the calling client's browser, even when that client is not able to access "internal-photoserver".

The above code sample will display the photo, but that will be the entire page. I'm rusty with ASP.NET, but I'm sure there's a simple way for this code to instead render the image to a placeholder, so you can display other stuff around the photo.

Disclaimer: I do have to add this bit of advice from MSDN:

Caution

Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions.

Sound advice (although what they're saying here is that instead of making the graphics classes either super-fast but unsafe or super-safe but slow, they instead chose unsafe and slow), and it might be possible to do this with plain-ol' System.IO instead, although I'm guessing that wouldn't work with all platforms (because of endianness and whatnot).

Update: Yep, this is a lot easier and safer:

protected void Page_Load(object sender, EventArgs e)
{
    HttpContext.Current.Response.Clear();
    HttpContext.Current.Response.ContentType = "image/jpeg";
    byte[] bytes = File.ReadAllBytes(
        @"\\internal-photoserver\shared drive\bobsmith.jpg");
    HttpContext.Current.Response.OutputStream.Write(bytes, 0, bytes.Length);
    HttpContext.Current.Response.End();
}
// need this using statement:
using System.IO;

This method would be better for heavy server usage, but you'd need to make sure the images were already in a browser-friendly format (not BMP). Plus, I'm think this would fail when serving up the images to platforms with a different byte ordering than your server, but I don't know.

The first method would be useful if the images were in a non-browser-ready format, or if you need to process them in some way before displaying (like shrinking them and making all their info look like a driver's license or something - I think programmers like me are the reason MSDN recommends not using System.Drawing in ASP.NET).

Finally: Well, I realized that the only reason the first two methods were showing an image in the browser was because the code was changing the content type to image and then sending an image's bytes, so you couldn't use this to display an image as part of an HTML page (i.e. with other text and stuff around it).

The only thing I could come up with was to have one page that just used the above method to write out an image to the response stream, and then another page with an IFRAME on it with its src set to the image page.

IFRAMEs are bad, or else they aren't. You could instead use a variant of this code and save the JPEG out to a temporary location on the public-facing server, and then build the login page so that it includes a link to this temporary file. You'd have to secure this file and clean it up eventually, of course.

There might be a much smoother, built-in way for ASP.NET to handle this problem, but you never know. I'm trying to get back up to speed with ASP.NET again after a relatively idle period, so it was more fun to chase this approach down.

MusiGenesis
A: 

One solution is to setup an HttpHandler to serve the photos. That way you can store the photos outside the website folder structure(or in App_Data) and perform any necessary authentication before serving up the photos.

Here is a great resource for setting up the image handler, although all the resizing, caching etc might be overkill for you needs. Essentially all you need is something like this:

public class myPhototHandler: IHttpHandler
{    
    
    public bool IsReusable {
        get { return true; }
    }
    
    public void ProcessRequest(System.Web.HttpContext context)
    {
        
            if (Context.User.Identity.IsAuthenticated) {
                var filename = context.Request.QueryString("f") ?? String.Empty;
                string completePath = context.Server.MapPath(string.Format("~/App_Data/Photos/{0}", path));
                context.Response.ContentType = "image/jpeg";
                context.Response.WriteFile(completePath);             
            }
       
    }
    
}

You obviously want to throw in some error checking, exceptions if the users not authenticated etc and register the handler in the web.config file. Then just set the image src to something like myPhototHandler.ashx?f=myphoto.jpg

geoff
A: 

There is indeed a much smoother, built-in way for ASP.NET to handle this problem. Add a new Generic Handler to your project named PhotoHandler:

<%@ WebHandler Language="C#" Class="PhotoHandler" %>

using System;
using System.Web;

public class PhotoHandler : IHttpHandler {

    public void ProcessRequest (HttpContext context) {
        string photoName = context.Request.QueryString["photoName"]; 
        context.Response.ContentType = "image/jpeg";
        context.Response.WriteFile(
            String.Format(
                @"\\internal-photoserver\shared drive\{0}.jpg", 
                photoName));
    }

    public bool IsReusable {
        get {
            return false;
        }
    }
}

To display an image from the non-public server, place (or build) an img element in your HTML, with its src property pointing to the handler, like this:

<img src="PhotoHandler.ashx?photoName=bob_smith" alt="If Bob Smith was a cat, 
    I would shave his ass and make him walk backwards." />

Note: I'm not sure the path to the photo server will work as written (I don't remember if UNC paths are supported or not), so you may have to map a drive instead.

MusiGenesis