Access uploaded files before PostbackTriggers

18 posts, 0 answers
  1. Massimiliano
    Massimiliano avatar
    184 posts
    Member since:
    Oct 2012

    Posted 10 Jan 2014 Link to this post

    I tryed several workarounds but wasn't able to find a way to do it.
    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..."}]}" ...
    All the file informations are present (including temp file name/dir in encripted JSON metadata field I suppose), could you suggest a workaround to parse this server side on button click even when PostbackTriggers is not fired? I think it's the only and simpliest solution so far for temporary uploaded files manipulation (like for example image preview...)

    Thanks in advance
  2. Hristo Valyavicharski
    Admin
    Hristo Valyavicharski avatar
    975 posts

    Posted 15 Jan 2014 Link to this post

    Hi Massimiliano,

    Here is how the AsyncUpload works, when its default configuration is used.
    1. You click on the "Select" button and select a file/s.
    2. The control automatically starts to upload it into the temporary
      (by default it is "App_Darta\RadUpload") via the upload handler.
    3. 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
    If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to the blog feed now.
  3. UI for ASP.NET Ajax is Ready for VS 2017
  4. Massimiliano
    Massimiliano avatar
    184 posts
    Member since:
    Oct 2012

    Posted 15 Jan 2014 Link to this post

    Hallo Hristo and thank you for your kind reply.
    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.

    .



  5. Hristo Valyavicharski
    Admin
    Hristo Valyavicharski avatar
    975 posts

    Posted 20 Jan 2014 Link to this post

    Hi Massimiliano,

    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
    If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to the blog feed now.
  6. Massimiliano
    Massimiliano avatar
    184 posts
    Member since:
    Oct 2012

    Posted 24 Jan 2014 Link to this post

    Hallo Hristo,
    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
  7. Hristo Valyavicharski
    Admin
    Hristo Valyavicharski avatar
    975 posts

    Posted 29 Jan 2014 Link to this post

    Hi Massimiliano,

    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
    If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the UI for ASP.NET AJAX, subscribe to the blog feed now.
  8. Massimiliano
    Massimiliano avatar
    184 posts
    Member since:
    Oct 2012

    Posted 29 Jan 2014 in reply to Hristo Valyavicharski Link to this post

    Hallo Hristo,
    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
  9. Massimiliano
    Massimiliano avatar
    184 posts
    Member since:
    Oct 2012

    Posted 29 Jan 2014 in reply to Massimiliano Link to this post

    Also what doesn't make sense to me is why we couldn't access that collection at any given moment before the final postback since the collection is there and submitted to the server every time (that's why I was able to use it with my custom script). I mean I don't understand the logic behind preventing this for any kind of operation with temp files. This would mean to move your temp files in another temp dir and manage them there and then move again them in a final dir if the form is submitted, wich really doesn't make much sense when we could simply access the uploaded files collection and retrieve temp files to do any kind of manipulation we need with them (ex. displaying thumbs, letting the user edit them somehow, and everything else BEFORE the actual form is confirmed, wich it may be never so the files would remain in the temp dir and get deleted)
  10. Hristo Valyavicharski
    Admin
    Hristo Valyavicharski avatar
    975 posts

    Posted 03 Feb 2014 Link to this post

    Hi Massimiliano,

    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
    If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the UI for ASP.NET AJAX, subscribe to the blog feed now.
  11. Massimiliano
    Massimiliano avatar
    184 posts
    Member since:
    Oct 2012

    Posted 03 Feb 2014 in reply to Hristo Valyavicharski Link to this post

    Thank you Hristo. Commented and voted ;)
    Guess this would be a nice addition making the control even for flexible to developers.
  12. Steve
    Steve avatar
    24 posts
    Member since:
    Jun 2010

    Posted 11 Jan 2015 Link to this post

    Was this request ever implemented?  I have a similar user scenario.  I have a file import feature that allows the user to upload a tab-delimited, comma-separated, or Excel file.  The user is allowed to map their file's columns to our standard database fields.  The user is also allowed to skip 0 or more "header" lines in the file.  Therefore, once the file is uploaded, we preview the first several lines and show these lines to the user.  If the user changes the number of header lines, then I would like to preview the file again with the new setting, to show what effect their choice had.  Once they have everything the way they want, then they click the final submit button, which triggers the actual import process into our database.  I need to be able to access the UploadedFiles collection across several postbacks, until they click the final submit button.  I am currently using the 2014.1.403.40 version, thank you.
  13. Hristo Valyavicharski
    Admin
    Hristo Valyavicharski avatar
    975 posts

    Posted 14 Jan 2015 Link to this post

    Hi Steve,

    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.

     
  14. Vasssek
    Vasssek avatar
    143 posts
    Member since:
    Aug 2010

    Posted 10 Feb in reply to Hristo Valyavicharski Link to this post

    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

    Vasssek
  15. Hristo
    Hristo avatar
    11 posts
    Member since:
    Jan 2013

    Posted 11 Feb in reply to Vasssek Link to this post

    Hi Vasssek,

     Use Query String Parameter

    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>

  16. Vasssek
    Vasssek avatar
    143 posts
    Member since:
    Aug 2010

    Posted 11 Feb in reply to Hristo Link to this post

    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

  17. Hristo
    Hristo avatar
    11 posts
    Member since:
    Jan 2013

    Posted 11 Feb in reply to Vasssek Link to this post

    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.

  18. Vasssek
    Vasssek avatar
    143 posts
    Member since:
    Aug 2010

    Posted 11 Feb in reply to Hristo Link to this post

    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

  19. Vasssek
    Vasssek avatar
    143 posts
    Member since:
    Aug 2010

    Posted 11 Feb in reply to Vasssek Link to this post

    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.

    http://www.telerik.com/forums/extended-asyncuploadhandler-fails-on-all-subsequent-uploads#cIEjERG6fkytyxEKXKqCEw

Back to Top
UI for ASP.NET Ajax is Ready for VS 2017