I have a user form (username, email, pass,...) where the user can upload an avatar.
What I'm trying to achieve here is that the user can upload the avatar and a thumbnail is shown, but until the form is ultimately submit (with a button wich is referenced in the PostbackTriggers) the avatar+thumb are not saved but stay in Telerik temp dir for uploaded files.
It seems that if I want to show the uploaded file while the user still has to complete and submit the whole form, I have to somehow trigger the PostbackTriggers otherwise I wan't be able to access the uploaded file to show it on the page.
On the other side, if I trigger PostbackTriggers when the user uploads the avatar (to show a preview of it) then I won't be able to access uploaded file when the form is ultimately submit since the RadAsyncUpload file collection has already been deleted.
What I don't understand in the logic implemented in this control is why I cannot access uploaded files collection unless PostBacktriggers are fired. I mean.... I can understand this to have the RadAsyncUpload_FileUploaded event fire automatically for each uploaded file when PostBacktriggers fires. This is a great implementation BUT I really don't understand why I shouldn't be able to access "manually" the collection even if PostBacktriggers are not fired with RadAsyncUpload.UploadedFiles.
On thing is to let the FileUploaded event fire when one of the PostBacktriggers is "clicked", another thing should be to be able to access manually the UploadedFiles collection at anytime server-side. I'm missing the logic behind this limitation in the control.
I really hope this possibility will be implemented, it will make most common integration scenarios much more seamless and really I don't understand why it should not be. In the meanwhile, since in the hiddenfield
id="ctl00_MainContent_RadAsyncUpload1_ClientState" ... value="{'isEnabled':'true','uploadedFiles':[{"fileInfo":{"FileName":"originalFileName.jpg","ContentType":"image/jpeg","ContentLength":4405,"DateJson":"2005-03-10T19:32:35.000Z","Index":0},"metaData":"CS8S/Z0J/b2982..."}]}" ...
Thanks in advance
17 Answers, 1 is accepted
Here is how the AsyncUpload works, when its default configuration is used.
- You click on the "Select" button and select a file/s.
- The control automatically starts to upload it into the temporary
(by default it is "App_Darta\RadUpload") via the upload handler. - After you cause a postback the file is moved from Temporary to the Target folder. Here you can set the PostBacktriggers property to specify which button will submit the file.
if you want to access the files on the server do not set TargetFolder property of the AsyncUpload, but handle
OnFileUploaded event (it will be fired for every file) or read those files on a button click.
For the described scenario I think it is better to use Custom Handler and make all the validation on the Client.
Regards,
Hristo Valyavicharski
Telerik
This is what I tested and how it works to my actual understanding:
- I don't have any TargetFolder set at all
- If I don't set any PostbackTriggers it posts back the file collection after the upload ended and triggers the OnFileUploaded event for each uploaded file.
The problem at this point is that if you later on confirm the form postback, you will have an empty UploadedFiles collection (since it has been alrady cleared on the last upload and OnFileUploaded event)
- If you setup PostbackTriggers so that the UploadedFiles collection is processed (and eventually OnFileUploaded event fired) correctly after the whole form postback, you won't be able to manipulate uploaded files (for example for the most common event of showing a preview of the uploaded image) unless you submit the whole form.
I think the idea behind PostbackTriggers property, to trigger the OnFileUploaded event for each file is really great and somehow "genial" BUT what I really dislike and don't understand in this control implementation is that I cannot access UploadedFiles collection during other events (like button clicks or such) for temporary processing of uploaded files.
Even more since the MainContent_RadAsyncUpload1_ClientState is always available so I really don't understand why we shouldn't access it at any time regardless of PostbackTriggers or OnFileUploaded event.
Thus until the control logic stays how it is now (hint and hope for a revision based on this suggestion) my best option is to "manually" access the MainContent_RadAsyncUpload1_ClientState to retrieve and manipulate temporary uploaded files.
So... any hint on the easiest way to extract temp file name from the json/encrypted metadata in MainContent_RadAsyncUpload1_ClientState value?
Thanks in advance.
.
I suggest that you to use Custom Handler and make the validation in the handler or on the client. The temporary file name will be passed as a parameter of the Process() method of the handler:
public
class
Handler : AsyncUploadHandler, System.Web.SessionState.IRequiresSessionState
{
protected
override
IAsyncUploadResult Process(UploadedFile file, HttpContext context, IAsyncUploadConfiguration configuration,
string
tempFileName)
{
var queryStringParam1 = context.Request.QueryString[
"saveToFolder"
];
string
targetFolder = context.Server.MapPath(
"~/Uploads/"
);
string
fileName = file.GetName();
file.SaveAs(targetFolder + fileName);
return
CreateDefaultUploadResult<UploadedFileInfo>(file);
}
}
Sample is attached.
Regards,
Hristo Valyavicharski
Telerik
thank you for your kind answer, but what I'm striving for is much simplier and shouldn't require mangling with the handler.
I found a workaround wich is still overkill considering that in my opinion this functionality should be offered natively from the controls, so that the UploadedFiles collection could be checked at any time server-side, regardless of the PostbackTriggers/OnFileUploaded event.
This is how I solved, I created and helper wich retrieves the original file name and the temp file name for every uploaded file and puts them in a dictionary.
Imports
Newtonsoft.Json.Linq
Namespace
Eva.Helpers
Public
Class
TelerikHelpers
Public
Function
GetTempUploadedFiles(asyncUpload
As
RadAsyncUpload)
As
Dictionary(Of
String
,
String
)
Dim
clientStateValue
As
String
= HttpContext.Current.Request.Form(asyncUpload.ClientID &
"_ClientState"
)
Dim
tempFiles
As
Dictionary(Of
String
,
String
)
If
Not
String
.IsNullOrWhiteSpace(clientStateValue)
Then
tempFiles =
New
Dictionary(Of
String
,
String
)
Dim
tempJsonFilesInfo
As
JArray =
DirectCast
(JObject.Parse(clientStateValue)(
"uploadedFiles"
), JArray)
Dim
tempFilesEncrypted
As
IDictionary(Of
String
,
String
) = tempJsonFilesInfo.ToDictionary(
Function
(o) o(
"metaData"
).ToString,
Function
(o) o(
"fileInfo"
)(
"FileName"
).ToString)
For
Each
kvp
As
KeyValuePair(Of
String
,
String
)
In
tempFilesEncrypted
Dim
jsonTempFileName
As
String
= JObject.Parse(Eva.Helpers.CryptoService.Decrypt(kvp.Key))(
"TempFileName"
).ToString
tempFiles.Add(System.IO.Path.Combine(AppSettings.ApplicationPhysicalPath,
"App_Data\RadUploadTemp\"
& jsonTempFileName), kvp.Value)
Next
End
If
Return
tempFiles
End
Function
End
Class
End
Namespace
I had to resort to Json.NET library (for simplicity in deserializing and querying what I needed) and a stripped down version of Telerik CryptoService class to decrypt the metadata.
THen I can access this helper this way in code behind:
Dim
uploadHelper
As
New
TelerikHelpers
Dim
uploadedFiles
As
Dictionary(Of
String
,
String
) = uploadHelper.GetTempUploadedFiles(RadAsyncUpload1)
Where the key is the temp file name (full path) and the value is the original file name.
Do you think it would be useful to open a feature request to access UploadedFiles collection natively at any time not only after triggers?
Thanks
I'm glad to read that you were able to found a solution. Regarding the feature request. There is no need to open it, because such functionality doesn't make sense. File are submitted on postback and then the UploadedFiles collection contains information about them. After that they are uploaded, which means that you probably finished to work with them. In case you need to have the newly saved files you may get their full names at the time, when the UploadedFiles collection was accessible. Same is valid when PostBackTriggers are used.
Regards,
Hristo Valyavicharski
Telerik
accessing the uploaded files collection before the final postback (so for example on a button click in the form, on a dropdownselect or just after an upload) makes sense in many scenarios where you need to handle temporary uploaded files before submission. The most common example that comes to my mind is showing the thumbnails of the file you uploaded before confirming and submitting the actual form but there may be several similar scenarios. If you look in this forum you'll find several requests on this subject
We are going to consider to add this functionality. That's why I have opened a new feature request. Please vote for it.
Thanks.
Regards,
Hristo Valyavicharski
Telerik
Guess this would be a nice addition making the control even for flexible to developers.
You could configure RadAsyncUpload to use Custom Handler. This way once the file is selected it transferred to the upload handler where you can read the file and return custom result back to the client
Similar to this demo http://demos.telerik.com/aspnet-ajax/asyncupload/examples/imageuploader/defaultcs.aspx
Regards,
Hristo Valyavicharski
Telerik
Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.
Hello,
I've implemented your custom handler, and it works as expected. I'm struggling now with this issue.
Let's say I want to add new parameter with e.g. guid id assigned to file name (customized file name), then append it to response context and on client side in OnClientFileUploaded I want to access (evaluate) it through args parameter value.
I tried to call context.Response.Write at the end of .ashx, but then javascript error had appeared that text is not good formatted, et
c...
Last line in the handler is return CreateDefaultUploadResult<UploadedFileInfo>(file);
Maybe If I was able to expand the <UploadedFileInfo> class, then I can append some new attribute ?
Please help me to solve this issue.
Thank you
Best regards
VasssekHi Vasssek,
protected
override
IAsyncUploadResult Process(UploadedFile file, HttpContext context, IAsyncUploadConfiguration configuration,
string
tempFileName)
{
var queryStringParam1 = context.Request.QueryString[
"first"
];
var queryStringParam2 = context.Request.QueryString[
"second"
];
SaveToDataBase(file, configuration, context, tempFileName, queryStringParam1, queryStringParam2);
return
CreateDefaultUploadResult<UploadedFileInfo>(file);
}
<
telerik:RadAsyncUpload
runat
=
"server"
ID
=
"RadAsyncUpload1"
MultipleFileSelection
=
"Automatic"
OnClientFileUploading
=
"onClientFileUploading"
></
telerik:RadAsyncUpload
>
<
script
type
=
"text/javascript"
>function onClientFileUploading(sender, args) {var obj = { first: 1, second: 2 }; args.set_queryStringParams(obj);}</
script
>
Hello,
Thank you for aour suggestion, but I need it in opposite way. As I wrote above, I want to create new parameter in IAsyncUploadResult Process method and return in back to client in Response.Write (mabye somehow through UploadedFileInfo class) and access it on OnClientFileUploaded method through args.
Vasssek
Browse the source code of this demo: AsyncUpload - Custom Http Handler
1. Custom Upload Result is created. It contains the parameter that you want to return:
using System;
using Telerik.Web.UI;
// The result object is returned from the handler to the page.
// You can include custom fields in the result by extending the AsyncUploadResult class.
// In this case we return the ID of the image record.
public class SampleAsyncUploadResult : AsyncUploadResult
{
private int imageID;
public int ImageID
{
get { return imageID; }
set { imageID = value; }
}
}
2. Set this parameter in the Process() method.
protected
override
IAsyncUploadResult Process(UploadedFile file, HttpContext context, IAsyncUploadConfiguration configuration,
string
tempFileName)
{
// Call the base Process method to save the file to the temporary folder
// base.Process(file, context, configuration, tempFileName);
// Populate the default (base) result into an object of type SampleAsyncUploadResult
SampleAsyncUploadResult result = CreateDefaultUploadResult<SampleAsyncUploadResult>(file);
int
userID = -1;
// You can obtain any custom information passed from the page via casting the configuration parameter to your custom class
SampleAsyncUploadConfiguration sampleConfiguration = configuration
as
SampleAsyncUploadConfiguration;
if
(sampleConfiguration !=
null
)
{
userID = sampleConfiguration.UserID;
}
// Populate any additional fields into the upload result.
// The upload result is available both on the client and on the server
result.ImageID = InsertImage(file, userID);
return
result;
}
3.Get this parameter through the args.get_fileInfo() object:
window.fileUploaded =
function
(sender, args) {
var
id = args.get_fileInfo().ImageID;
$(
".imageContainer"
)
.html(
""
)
.append($(
"<img />"
)
.attr(
"src"
, getImageUrl(id)));
$(
".info"
).html(String.format(
"<strong>{0}</strong> successfully inserted.<p>Record ID - {1}</p>"
, args.get_fileName(), id));
};
I hope this helps.
Hello,
thank you for suggestion.
Because I don't need to obtain any custom information passed from the page, I slightly modify code in IAsyncUploadResult Process method...
It works as expected. Now, I'm able to get custom parameters on client side after file has been uploaded to server :-)
Best regards
Vasssek
I had problems with subsequent uploading. The initial upload works as expected. A subsequent upload does process the file, but a javascript error occurs...
For those who experienced similar issue here is the link which solve it.