Configuration Setup
First define the necessary settings in appsettings.json:
{
"SharedFolderSettings": {
"RemotePath": "\\\\192.168.1.200\\Files",
"PublicBaseUrl": "http://files.example.com/",
"User": "shareuser",
"Password": "sharepassword"
}
}
Create a corresponding options class:
public class SharedFolderOptions
{
public string RemotePath { get; set; }
public string PublicBaseUrl { get; set; }
public string User { get; set; }
public string Password { get; set; }
}
Bind the configuration section in Program.cs (minimal hosting) or Startup.cs:
builder.Services.Configure<SharedFolderOptions>(
builder.Configuration.GetSection("SharedFolderSettings"));
Establishing a Credentialed Connection
Windows shares require authentication before file operations. A disposable helper that uses the Windows Networking API (mpr.dll) is cleaner than spawning a command‑line process:
using System.Runtime.InteropServices;
public class NetworkShareConnection : IDisposable
{
[StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
public string lpLocalName;
public string lpRemoteName;
}
[DllImport("mpr.dll", CharSet = CharSet.Auto)]
private static extern int WNetUseConnection(
IntPtr hwndOwner,
NETRESOURCE lpNetResource,
string lpPassword,
string lpUserID,
int dwFlags,
string lpAccessName,
string lpBufferSize,
string lpResult);
[DllImport("mpr.dll", CharSet = CharSet.Auto)]
private static extern int WNetCancelConnection2(
string lpName,
int dwFlags,
bool fForce);
private readonly string _remotePath;
private bool _disposed;
public NetworkShareConnection(string remotePath, string user, string password)
{
_remotePath = remotePath;
var netRes = new NETRESOURCE
{
dwType = 1, // RESOURCETYPE_DISK
lpRemoteName = remotePath
};
int result = WNetUseConnection(IntPtr.Zero, netRes, password, user, 0, null, null, null);
if (result != 0)
throw new IOException($"Cannot connect to share. Error code: {result}");
}
public void Dispose()
{
if (!_disposed)
{
WNetCancelConnection2(_remotePath, 0, force: true);
_disposed = true;
}
}
}
Streaming the Uploaded File to the Share
After a successful connection, writing the incoming file stream to the network location is straightforward:
public static class FileTransferHelper
{
public static void SaveToShare(Stream source, string folderPath, string fileName)
{
if (!Directory.Exists(folderPath))
Directory.CreateDirectory(folderPath);
string fullPath = Path.Combine(folderPath, fileName);
if (File.Exists(fullPath)) return; // optional: handle duplicates
using var destination = new FileStream(fullPath, FileMode.CreateNew, FileAccess.Write);
source.CopyTo(destination);
}
}
Controller Implementation
The file upload endpoint receives the multipart form data, generates a unique file name, opens a share connection, and stores the file. The public URL is constructed from the configured base address.
[ApiController]
[Route("api/[controller]")]
public class FilesController : ControllerBase
{
private readonly SharedFolderOptions _settings;
public FilesController(IOptions<SharedFolderOptions> options)
{
_settings = options.Value;
}
[HttpPost("upload")]
public IActionResult UploadFile()
{
var file = Request.Form.Files.FirstOrDefault();
if (file == null) return BadRequest("No file provided.");
string originalName = Path.GetFileName(file.FileName);
string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
string storedName = $"{timestamp}_{originalName}";
// Organize files in date‑based subdirectories
string subFolder = DateTime.UtcNow.ToString("yyyy\\/MM\\/dd");
string remoteDirectory = Path.Combine(_settings.RemotePath, subFolder);
string relativePath = $"{subFolder}/{storedName}";
try
{
using var connection = new NetworkShareConnection(
_settings.RemotePath,
_settings.User,
_settings.Password);
FileTransferHelper.SaveToShare(file.OpenReadStream(), remoteDirectory, storedName);
string publicUrl = $"{_settings.PublicBaseUrl.TrimEnd('/')}/{relativePath}";
return Ok(new { publicUrl, relativePath });
}
catch (Exception ex)
{
return StatusCode(500, $"Upload failed: {ex.Message}");
}
}
}
Important Considerations
- Directory permissions: The configured Windows user must have write access to the share.
- Thread safety: The
NetworkShareConnectionties the connection to the current thread; avoid sharing it across tasks without testing. - Error recovery: In production, add retry logic and ensure connections are always disposed evenif exceptions occur.