Tuesday, March 21, 2006

Accessing Shared Folders in ASP.NET

Believe me its easy. If only you wont get caught up with the 'Impersonation' word. A lot of sites took me for a jolly ride on the Impersonation road. Luckily I found the answer on Experts Exchange.

Here's a demo of the code:


using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Net;

public class ShareThis {
//used in calling WNetAddConnection2[StructLayout (LayoutKind.Sequential)]
public struct NETRESOURCE {
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;

[MarshalAs(UnmanagedType.LPStr)]
public string lpLocalName;

[MarshalAs(UnmanagedType.LPStr)]
public string lpRemoteName;

[MarshalAs(UnmanagedType.LPStr)]
public string lpComment;[MarshalAs(UnmanagedType.LPStr)]
public string lpProvider;
}

//WIN32API - WNetAddConnection2
[DllImport("mpr.dll",
CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int WNetAddConnection2A(
[MarshalAs(UnmanagedType.LPArray)]NETRESOURCE[] lpNetResource,
[MarshalAs(UnmanagedType.LPStr)]string lpPassword,
[MarshalAs(UnmanagedType.LPStr)]string lpUserName,
int dwFlags);

//WIN32API - WNetCancelConnection2
[DllImport("mpr.dll",
CharSet = System.Runtime.InteropServices.CharSet.Auto)]

private static extern int WNetCancelConnection2A(
[MarshalAs(UnmanagedType.LPStr)]string lpName, int dwFlags, int fForce);
public static void CopyFile(string share, string username, string password,
string dirFrom, string dirTo, string filename){
NETRESOURCE[] nr = new NETRESOURCE[1];
nr[0].lpRemoteName = share;
nr[0].lpLocalName = "";

//mLocalName;nr[0].dwType = 1;
//disknr[0].dwDisplayType = 0;

nr[0].dwScope = 0; nr[0].dwUsage = 0;
nr[0].lpComment = "";
nr[0].lpProvider = "";

WNetAddConnection2A(nr, password, username, 0);
File.Copy(dirFrom + "\\" + filename, dirTo + "\\" + filename);

WNetCancelConnection2A(share, 0, -1);
}

public static void Main(string[] args) {

CopyFile(@"\\sa191", "username", "password",
@"f:\shared", @"\\sa191\shared", "123.shp");
}
}

25 comments:

Anonymous said...

Hi,
Your code for moving file to network share really helped me.


Thankyou,
Mahesh.
Developer.

Anonymous said...

That looks great...

But do you have a VB version?

Agnel CJ Kurian said...

VB version should be easy. ;)

Anonymous said...

Hey how Do I acieve Reverse ??

i.e from n/w to client machine ??

Agnel CJ Kurian said...

Swap the 4th and 5th arguments to CopyFile()

Anonymous said...

YOU SO TOTALLY ROCK! This works wonderfully. I took your code and modified it to what i needed.

Anonymous said...

Do you know if the password encrypted over the network?

Agnel CJ Kurian said...

@kjsteuer
I am not sure of that. You can read more about the SMB protocol to get that answer (SMB is how we access shared folders on Windows).

amirLURVEnabilah said...

hi..this code really help me..
do you know how to open or download files from the shared folder?

K Siva Karthikeyan said...

Is it possible to retrive the contents of the shared folders i.e. name of the files using simillar method . any inputs?

Sabarishbabu said...

Hi,
1.I am using your example to create a Directory in our shared network (FileServer is part of our network).
2.I followed your code to copy a file.
3. It works successfully when I gave the source and destination machines are same. Able to copy a file.
But, I am getting "Exception - Logon failure: unknown user name or bad password." error when I am gave the different machine name
Like
CopyFile(@"\\sfg22-135561864", "SFG22", "welcome", @"E:\shared",
@"\\192.168.1.65\d\Files", "123.txt");.

Any ideas/clues

Thanks a lot for your quick response
Sabarish
sabarishbabu@gmail.con

Sabarishbabu said...

Hi,
1.I am using your example to create a Directory in our shared network (FileServer is part of our network).
2.I followed your code to copy a file.
3. It works successfully when I gave the source and destination machines are same. Able to copy a file.
But, I am getting "Exception - Logon failure: unknown user name or bad password." error when I am gave the different machine name
Like
CopyFile(@"\\sfg22-135561864", "SFG22", "welcome", @"E:\shared",
@"\\192.168.1.65\d\Files", "123.txt");.

Any ideas/clues

Thanks a lot for your quick response
Sabarish
sabarishbabu@gmail.con

Agnel CJ Kurian said...

@amirLURVEnabilah
You should be able to use ShellExecute to attempt 'opening' the file. Downloading? That is what my sample code does.

@Siva
.NET has File,Path and Directory classes. Try some of the static methods.

@Sabarishbabu
I think you will have to make another call to WNetAddConnection2A with the login and password to the second machine.

Sorry for the late reply.

adeel said...

When I tried your code on my local machine in visual Studio 2008 with a shared path CopyFile works fine.

When I tried same code on Windows Server 2008 with IIS 7 gives error Access denied to the path, but I can share the path on server manualy.

Please advise me what I am doing wrong.

Agnel CJ Kurian said...

The folder must be shared before calling the function. The function only copies files; it does not share any folders.

adeel said...

The folder is shared.

Agnel CJ Kurian said...

@adeel
Explain this: "When I tried same code on Windows Server 2008 with IIS 7 gives error Access denied to the path, but I can share the path on server manualy."

adeel said...

Hi Kurian,

Thank for your unstant reply.

The folder on the remote machine as shared and have full control a shared user everyone, which is on both machine with same name and passowrd and Administrator rights.

Remote machine running Windows vista business.

please see source code below.

public class ShareThis
{

private const string share=@"\\192.168.100.100\shared";
private const string RemoteDir = @"\\192.168.100.100\shared";
private const string LocalDir = @"c:\local";
private const string username = "username";
private const string password = "password";


//used in calling WNetAddConnection2
[StructLayout (LayoutKind.Sequential)]
public struct NETRESOURCE
{
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
[MarshalAs(UnmanagedType.LPStr)]
public string lpLocalName;
[MarshalAs(UnmanagedType.LPStr)]
public string lpRemoteName;
[MarshalAs(UnmanagedType.LPStr)]
public string lpComment;
[MarshalAs(UnmanagedType.LPStr)]
public string lpProvider;
}
//WIN32API - WNetAddConnection2
[DllImport("mpr.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int WNetAddConnection2A([MarshalAs(UnmanagedType.LPArray)] NETRESOURCE[] lpNetResource,
[MarshalAs(UnmanagedType.LPStr)] string lpPassword,
[MarshalAs(UnmanagedType.LPStr)] string lpUserName,
int dwFlags);
//WIN32API - WNetCancelConnection2
[DllImport("mpr.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int WNetCancelConnection2A([MarshalAs(UnmanagedType.LPStr)] string lpName, int dwFlags, int fForce);

//public static void CopyFile(string share, string username, string password, string dirFrom, string dirTo, string filename)
public static void CopyFileToPAF(string filename)
{
NETRESOURCE[] nr = new NETRESOURCE[1];
nr[0].lpRemoteName = share;
nr[0].lpLocalName = "";
//mLocalName;
nr[0].dwType = 1;
//disk
nr[0].dwDisplayType = 0;
nr[0].dwScope = 0;
nr[0].dwUsage = 0;
nr[0].lpComment = "";
nr[0].lpProvider = "";
WNetAddConnection2A(nr, password, username, 0);
File.Copy(LocalDir + "\\" + filename, RemoteDir + "\\" + filename, true);
WNetCancelConnection2A(share, 0, -1);
}

public static void CopyFileToLocal(string filename)
{
NETRESOURCE[] nr = new NETRESOURCE[1];
nr[0].lpRemoteName = share;
nr[0].lpLocalName = "";
//mLocalName;
nr[0].dwType = 1;
//disk
nr[0].dwDisplayType = 0;
nr[0].dwScope = 0;
nr[0].dwUsage = 0;
nr[0].lpComment = "";
nr[0].lpProvider = "";
WNetAddConnection2A(nr, password, username, 0);
File.Copy(RemoteDir + "\\" + filename, LocalDir + "\\" + filename,true);
WNetCancelConnection2A(share, 0, -1);
}

Agnel CJ Kurian said...

I'd check to see if the access denied error is happening on the source or the destination. Have a closer look at the exception and let me know.

adeel said...

error: Access to the path '\\192.168.100.100\shared\Adeel.txt' is denied.

Unknown said...

Hi Adeel, I'm facing the same problem as yours, did you manage to solve it please ?

Thanx

adeel said...

The code below is working fine, I was just doing a mistake passing Remote machine name instate of local_machine name, tha solve the problem.

let me know if this not works.
***********************************
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Security.Principal;
using System.Runtime.InteropServices;

/// summary
/// Summary description for ImpersonateUser

public class ImpersonateUser
{
// Declare signatures for Win32 LogonUser and CloseHandle APIs
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool LogonUser(
string principal,
string authority,
string password,
LogonSessionType logonType,
LogonProvider logonProvider,
out IntPtr token);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
enum LogonSessionType : uint
{
Interactive = 2,
Network,
Batch,
Service,
NetworkCleartext = 8,
NewCredentials
}
enum LogonProvider : uint
{
Default = 0, // default for platform (use this!)
WinNT35, // sends smoke signals to authority
WinNT40, // uses NTLM
WinNT50 // negotiates Kerb or NTLM
}



static WindowsImpersonationContext wic;

public ImpersonateUser() { }
private static WindowsImpersonationContext impersonatedUser = null;
private static IntPtr token = new IntPtr(0);


public void Impersonate(string username)
{
//IntPtr token = IntPtr.Zero;
token = IntPtr.Zero;


try
{
// Create a token for DomainName\Bob
// Note: Credentials should be encrypted in configuration file
bool result = LogonUser(username, "LOCAL_SERVER_NAME",
"LOGIN_PASSWORD",
LogonSessionType.NetworkCleartext,
LogonProvider.Default,
out token);
if (result)
{
WindowsIdentity id = new WindowsIdentity(token);

// Begin impersonation
impersonatedUser = id.Impersonate();
// Log the new identity

}
else
{
Email.sendError("adeel@xxx.com", "Error (I/O) impersonate failed: " +username + " ", Marshal.GetLastWin32Error().ToString());
}
}
catch (Exception ex)
{
Email.sendError("adeel@xxx.com", "Error (I/O) impersonate: "+username + " ", ex.Message);
// Prevent any exceptions that occur while the thread is
// impersonating from propagating
}
}

// Stops impersonation
public void Undo()
{
if (impersonatedUser != null)
{
impersonatedUser.Undo();
// Free the tokens.
if (token != IntPtr.Zero)
CloseHandle(token);

// Email.sendError("adeel@xxx.com", "impersonate Undo: ", "impersonate Undo: ");
}
}



}

十二月 said...

Hi,

I'm new in asp.net, C#. Your code is quite complicated for me. I don't really get it. Can you explain further? Currently I'm doing a web application, and I want to access to shared folder. Can you please help take a look on my codes below?

string strPhysicalPath = @"\\SharedFolder\File\";
FileInfo objFileInfo = new FileInfo(strPhysicalPath);
Response.Clear();
Response.CacheControl = "private";
Response.Expires = -1;
Response.ContentType = "application/octet"; Response.AddHeader("Content-Disposition", "attachment; filename=testing.bmp");

FileStream fs = new FileStream(strPhysicalPath, FileMode.Open, FileAccess.Read);
byte[] buffer = new Byte[objFileInfo.Length];
fs.Read(buffer, 0, (int)objFileInfo.Length); Response.BinaryWrite(buffer);

fs.Close();
Response.End();

Is there something wrong with my code?

Regards,
Howyi

Adeel said...

you need to Impersonate to access a shared folder from IIS.

Please follow the example above.

十二月 said...

Hi Adeel,

I have found the solution for my problem. I didn't notice that I need to specify the file name instead of just specify the path name. Example: string strPhysicalPath = @"\\SharedFolder\File\testing.doc";

Anyway, thanks for the reply.

Regards,
Howyi

About Me

My photo
C/C++ Programmer doing CAD on Windows. Some web development experience. Bangalorean.

Blog Archive

Labels