Hello Jeff!
Good point you raised. As Ext.NET is but an ExtJS framework, we tend to add support to their controls as they are, and make modifications only when they don't work. Maybe it does not make much sense in just having a file select in ExtJS, they already did it with upload functionality and didn't expect anyone to need it. Me might consider building a simpler button type=File if really necessary.
As a matter of fact, we did implement our own variation of control that handles uploads, although not as simple as
<input type=file ...
, it can mimic pretty well the behavior, including by not locking any file handlers by the browser. Below is a couple adaptations on your original sample to use
MultiUpload
control:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
var fileName;
var importData = function () {
console.log(fileName);
if (typeof (fileName) == 'undefined') {
alert("Select a file... before trying to send.");
return;
}
console.log('will load "'+fileName+'"')
Ext.net.DirectMethod.request({
url: '@(Url.Action("Import"))',
params: { fileName: fileName }
});
};
var bindFileName = function (item, file, errorCode, message) {
console.log("Selected file");
fileName = file.name;
}
</script>
</head>
<body>
@Html.X().ResourceManager().ScriptMode(Ext.Net.ScriptMode.Debug).SourceFormatting(true)
@(Html.X().GridPanel().Width(900)
.Title("Users").ID("GridPanel").Border(true)
.Store(Html.X().Store().ID("Store")
.Model(Html.X().Model().ID("Model").IDProperty("ID")
.Fields(
new ModelField("ID", ModelFieldType.Int),
new ModelField("Name"),
new ModelField("Period")
)
)
.Proxy(Html.X().AjaxProxy().Url(Url.Action("Read")).Reader(Html.X().JsonReader().RootProperty("data"))))
.ColumnModel(
Html.X().Column().Text("Name").DataIndex("Name").Flex(20),
Html.X().Column().Text("Period").DataIndex("Period").Flex(20).ID("Period")
)
.TopBar(
Html.X().Toolbar()
.Items(
Html.X().MultiUpload().ID("mupload")
.AutoStartUpload(false)
.FileTypes("*.*")
.FileTypesDescription("All files")
.Listeners(listener => listener.FileSelected.Fn="bindFileName"),
Html.X().ToolbarSeparator(),
Html.X().Button().Text("Import Data").Icon(Icon.PageExcel).Listeners(lst => lst.Click.Fn = "importData")
)
)
)
</body>
</html>
A text field with the filename could be added and value bound in the "bindFileName" function. Left out for simplicity.
Thus the
Import
action would be:
public ActionResult Import(string fileName)
{
FileStream fileStream = System.IO.File.Open(Path.Combine(@"A:\Temp\", fileName), FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
X.AddScript(@"console.log('opened \'" + fileName + @"\'');");
fileStream.Close();
return this.Direct();
}
Notice the MemoryStream approach is still desirable if you want to keep the file opened after running the
Import
method. If you don't close the file now, IIS (or IISExpress) will be locking the file for the life of the session despite the
FileShare
flag allowing other instances reading it.