23 Answers, 1 is accepted
We do not have plans to expose any events in the Upload handler. However there are some useful methods that you can use from the base handler:
public virtual bool IsNewFileRequest() - this method will return True, when this is the first request for the upcoming file.
public virtual bool IsFinalFileRequest() - this method will return True, when this is the final request for the upcoming file.
public
virtual bool IsFinalUpload() - this method will return True, when this is last request for all the files that will be uploaded with the current upload session e.g. if user is uploading 10 files this method will return true only when the last file is making its final post request.
Is this be enough for you? Do you think we can make another helpful methods/properties in the base handler? Let us know - we are actively looking for feedback on this.
Thanks!
Greetings,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
So, there are a few things that would be helpful to me:
1) An event or method that I can override/implement before the save to write either the meta information to the DB.
2) An event or method that I can override/implement which would allow me to do the save (so I can change the filename -- for one application we write the file name as a key in a document management table).
3) An event or method after the save so that I could log an error if there was a problem with the save.
As you know the RadUpload is doing the file upload in small chunks - e.g. there are several requests created for a single file to be uploaded.
You can override the ProcessStream method. Calling the base method will write the file on the file system. Then you can check if this is the final request for this file. If this is the final request then you can hook up your logic for either renaming the file of insterting it into the DB.
Here is a sample implementation:
<%@ WebHandler Language="C#" Class="RadUploadHandler" %> |
using System; |
using System.Web; |
using System.IO; |
public class RadUploadHandler : Telerik.Windows.RadUploadHandler |
{ |
public override void ProcessStream() |
{ |
base.ProcessStream(); |
if (this.IsFinalFileRequest()) |
{ |
string filePath = this.GetFilePath(this.Request.Params["RadUAG_FileName"]); |
FileStream stream = File.OpenRead(filePath); |
// your custom logic for insert in DB/rename/etc.. goes here |
} |
} |
} |
Kind regards,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Thanks for your responses. It's actually very difficult for me to evaluate the upload right now, because I just do not have enough information in terms of what I'm working with to do the upload. Am I missing some documentation or something? I have the .chm files and the examples project and don't see a way to do what I would like to do.
I am definitely new to the Telerik upload stuff, so maybe that's part of it, but I have implemented the server-side upload for NeatUpload, the default Asp .net upload component, and the Flex FlashFileUpload component (which is very nice by the way)
I might be missing something, but the Flex upload on my local computer is about 10x as fast as the current Telerik Beta upload. (Just a suggestion to look at their implementation which is all open source to evaluate if there's a way to speed up the upload.)
I'm planning on purchasing the Telerik package before the end of the month to get Silverligh, but it would help me evaluate if I can use the Telerik upload if I could get more documentation. For example, I had no idea RadUAG_FileName was a parameter and don't know where to find that.
Anyway, any more documentation would be greatly appreciated. What I want to do is get custom data passed in from Silverlight, change the save directory based on this data, but rename the file as a differnt name, and store the meta information in a DB.
I'm used to having the HttpContext so that I can do the save, but I know that the handler is implemented differently than the way that the Flex, NeatUpload, and Asp.net ones do it.
Once again, thanks for your help. If you give me some hints here, I can even post my basic source to help others out!
Chris
You are right about the documentation. The controls are still in beta version and the documentation is definitely not first class. Especially the Upload control has some major help topics in draft and not yet published. We've got a lot of questions and feedback about the upload control and by the time of next release (scheduled for the end of next week) we will improve the help with the major missing topics. You can see the current online help for RadUpload here:
API reference:
http://www.telerik.com/help/silverlight/telerik.windows.controls.input-telerik.windows.controls.radupload_members.html
Help articles:
http://www.telerik.com/help/silverlight/radupload-overview.html
About the performance: The performance of the RadUpload is very dependant on the BufferSize property. Before each file is uploaded it is split into a couple of small chunks. The size of the chunk is determined from the BufferSize property. Each chunk is uploaded to the server side handler in a separate request. So, if you have small BufferSize the upload control will make many chunks, thus -> many requests to the handler which can be slow. Try making the BufferSize property bigger - this should increase the RadUpload performance.
As for the custom parameters for each file - this is currently in development - feature will be available as part of the next week release. You will be able to pass custom parameters from the Silverlight client and then read it in the server handler.
I hope this makes the picture about the RadUpload much more clear now. Let us know if you have any other questions in order to evaluate our Silverlight suite. Your feedback is greatly appreciated.
Sincerely yours,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
I'm just taking another look at the upload and since I can't see the source for ProcessStream I can't really override it with maintaining the functionality required to get it to work.
If you could provide a way to change the filename/directory for an individual file in the save, that would be great. Basically, I want to save the file as a name after executing some code (adding a row into a DB).
I think I mentioned this before, but thought I'd post again so that hopefully something might be done before the end of the week (next release).
Thanks,
Chris
I'm attaching the source code for the base upload handler for your convenience. Take a look at the ProcessStream method - it contains all the logic for working/saving the files. You can override this method and implement your own logic into your derived class.
Greetings,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
I should be able to code and do all that I need now that I know the flow of the code. Basically, overriding GetTargetFolder, GetFileName, and ProcessStream gives me enough functionality to do the upload where I want it and storing the info.
The one piece of information that I am missing though is how to pass custom data back to the SL app, especially on an UploadFinished event, but it would be helpful on other events too.
Can you help me out with what I need to do that?
Thanks,
Chris
Great to see that you have progress on this! Your feedback on the Rad Upload control is very much appreciated. We are currently performing some code refactoring and help topics based on the user feedback we have, so I hope that with the next version the Upload control will be much more flexible and easy to use.
For the custom returned data - you can override the AssociatedData virtual property of the handler and to return the data you want. In the file I send you yesterday there is a commented code that you can use as an example about how to return the data you want. I'm pasting the same code here also:
public virtual string AssociatedData |
{ |
get |
{ |
Dictionary<string, object> customData = new Dictionary<string, object>(); |
customData.Add("myCustomKey", "myCustomKeyValue"); |
customData.Add("myCustomKey2", 777); |
string output = ""; |
foreach (string key in customData.Keys) |
{ |
string value; |
if (customData[key] is bool) |
{ |
value = ((bool)customData[key]) ? "true" : "false"; |
} |
else |
{ |
value = "\"" + customData[key].ToString().Replace("\\", "\\\\") + "\""; |
} |
output += "{" + String.Format(@"""Key"":""{0}"",""Value"":{1}", key, value) + "},"; |
} |
output = output.TrimEnd(','); |
return output; |
} |
} |
On the client this data is available in the FileUploaded event args. It is stored in the "associatedData" key of the HandlerData property of the FileUploadedEventArgs.
Best wishes,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Great, I'll try this out tomorrow and post some code if I get the whole thing working.
Thanks a lot!
private Dictionary<string, object> GetAssociatedData(FileUploadedEventArgs e) |
{ |
object[] associatedData = e.HandlerData["associatedData"] as object[]; |
Dictionary<string, object> data = new Dictionary<string,object>(); |
if (associatedData != null) |
{ |
foreach (object k in associatedData) |
{ |
object[] subObject = k as object[]; |
System.Collections.Generic.KeyValuePair<string, object>? key = subObject[0] as System.Collections.Generic.KeyValuePair<string, object>?; |
System.Collections.Generic.KeyValuePair<string, object>? value = subObject[1] as System.Collections.Generic.KeyValuePair<string, object>?; |
if ((key != null) && (value != null)) |
{ |
data.Add(key.Value.Value as string, value.Value.Value); |
} |
} |
} |
return data; |
} |
Handler code:
private void rulImage_FileUploaded(object sender, FileUploadedEventArgs e) |
{ |
Dictionary<string, object> returnValues = GetAssociatedData(e); |
string newFile = returnValues["JT_FileName"] as string; |
if (!string.IsNullOrEmpty(newFile)) |
{ |
newFile = newFile.Replace("\\\\", "\\"); |
newFile = newFile.Replace("//", "/"); |
_currentData.ImageFile = newFile; |
Uri uri = new Uri(_currentData.ImageFile.Replace("~", AppContext.BASE_URL), UriKind.Absolute); |
ImageSource img = new System.Windows.Media.Imaging.BitmapImage(uri); |
imgCategory.SetValue(Image.SourceProperty, img); |
} |
} |
I'll need to strip out my code a bit to hide a little of the custom implementation, but I'll try to pasted the full-up code that I'm using to get this to work soon.
Unfortunately this is the only way for the moment. We will release new version of the RadUpload this week where we will have better mechanism for playing with the data on the client. I'll modify this example to work with the latest RadUpload bits and will let you know in a couple of days. Is this ok?
Greetings,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
That's fine with me. Thanks for your help. I'm sure the upload is going to be a great control.
first of all - thank you for your patience. Now that the RC is out here is the syntax that should be used when dealing with custom parameters:
When you need to pass some information to the server side handler you have two options:
- Use the AdditionalPostFields property and specify parameters that will be sent with every request to the upload handler, for all the files that will be uploaded
public Page() { InitializeComponent(); Loaded += new RoutedEventHandler(Page_Loaded); } void Page_Loaded(object sender, RoutedEventArgs e) { RadUpload1.AdditionalPostFields.Add("myParam1", "myParam1Value"); } - Handle the FileUploadStarting event and set parameters that are specific to this file and will be sent with the request for this file only. Here is an example:
private void RadUpload_FileUploadStarting(object sender, FileUploadStartingEventArgs e) { RadUpload upload1 = sender as RadUpload; e.FileParameters.Add("myParam1", "myParam1Value"); }
All parameters are sent as ordinary post parameters. They are accessible in the event handler in the following way:
string myParamValue = this.Request.Form["myParam1"];
To return custom parameters from the upload handler override the GetAssociatedData() method and return a dictionary with the parameters that you want to pass to the client event handler.
public class RadUploadHandler : Telerik.Windows.RadUploadHandler |
{ |
public override Dictionary<string, object> GetAssociatedData() |
{ |
Dictionary<string, object> dict = new Dictionary<string, object>(); |
dict.Add("myParam1", "myParam1Value"); |
dict.Add("myParam2", true); |
dict.Add("myParam3", 125); |
dict.Add("myParam4", 12.5); |
return dict; |
} |
} |
To get the parameters returned from the handler you should handle the FileUploaded event:
private void RadUpload_FileUploaded(object sender, FileUploadedEventArgs e) |
{ |
RadUploadSelectedFile uploadedFile = e.SelectedFile; |
string myParam1Value = e.HandlerData.CustomData["myParam1"]; |
} |
Please let us know if you have any feedback on this.
Sincerely yours,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Great, I was able to get this to work. It is cleaner now which is good.
Here's my code for the Web Handler (server side). I cleaned it up/took out some of the implementation a bit and didn't include my WcfServiceUtils call, but it should basically be a way to handle adding an image onto the file system and storing the info in database.
<%@ WebHandler Language="C#" Class="TestHandler" %> |
using System; |
using System.Web; |
using System.Collections; |
using System.Collections.Generic; |
using System.Linq; |
using System.Data.Linq; |
using System.IO; |
public class TestHandler : Telerik.Windows.RadUploadHandler |
{ |
protected Dictionary<string, object> _customValues; |
protected string BuildPhysicalDirectory(ArrayList subDirs, bool isPublic) |
{ |
try |
{ |
if (subDirs == null) return null; |
string baseDir = "App_Data"; |
if (isPublic) |
baseDir = "Data"; |
string currPhysPath = System.IO.Path.Combine(this.Context.Request.PhysicalApplicationPath, baseDir); |
foreach (string dir in subDirs) |
{ |
currPhysPath = System.IO.Path.Combine(currPhysPath, dir); |
} |
return currPhysPath; |
} |
catch (System.Web.HttpException e) |
{ |
jt_Error_Log error = new jt_Error_Log(); |
error.Description = "Could not build phys path"; |
error.Error_Code = -1; |
error.Error_Date = DateTime.Now; |
error.Module_Name = "Upload Handler"; |
error.Filename = "TestHandler.ashx"; |
JtDataContext db = new JtDataContext(); |
db.jt_Error_Logs.InsertOnSubmit(error); |
db.SubmitChanges(); this.AddReturnParam("message", e.Message); |
return null; |
} |
} |
protected string BuildRelativeDirectory(ArrayList subDirs, bool isPublic) |
{ |
try |
{ |
if (subDirs == null) return null; |
string baseDir = "~/App_Data"; |
if (isPublic) |
baseDir = "~/Data"; |
string currPhysPath = baseDir; |
foreach (string dir in subDirs) |
{ |
currPhysPath = System.IO.Path.Combine(currPhysPath, dir); |
} |
return currPhysPath; |
} |
catch (System.Web.HttpException e) |
{ |
jt_Error_Log error = new jt_Error_Log(); |
error.Description = "Could not build relative dir"; |
error.Error_Code = -1; |
error.Error_Date = DateTime.Now; |
error.Module_Name = "Upload Handler"; |
error.Filename = "TestHandler.ashx"; |
JtDataContext db = new JtDataContext(); |
db.jt_Error_Logs.InsertOnSubmit(error); |
db.SubmitChanges(); this.AddReturnParam("message", e.Message); |
return null; |
} |
} |
protected bool EnsureDirectoryStructExists(HttpContext context, ArrayList subDirs, bool isPublic) |
{ |
string baseDir = "App_Data"; |
if (isPublic) |
baseDir = "Data"; |
bool exists = false; |
try |
{ |
string currPhysPath = System.IO.Path.Combine(context.Request.PhysicalApplicationPath,baseDir); |
// Make sure the directory structure exists |
DirectoryInfo di = new DirectoryInfo(currPhysPath); |
// Create the directory only if it does not already exist. |
if (!di.Exists) |
di.Create(); |
foreach(string dir in subDirs) |
{ |
currPhysPath = System.IO.Path.Combine(currPhysPath, dir); |
DirectoryInfo diSub = new DirectoryInfo(currPhysPath); |
// Create the directory only if it does not already exist. |
if (!diSub.Exists) |
diSub.Create(); |
} |
} |
catch (System.Web.HttpException e) |
{ |
this.AddReturnParam("message", e.Message); |
jt_Error_Log error = new jt_Error_Log(); |
error.Description = "Could not write path"; |
error.Error_Code = -1; |
error.Error_Date = DateTime.Now; |
error.Module_Name = "Upload Handler"; |
error.Filename = "TestHandler.ashx"; |
JtDataContext db = new JtDataContext(); |
db.jt_Error_Logs.InsertOnSubmit(error); |
db.SubmitChanges(); |
return false; |
} |
return true; |
} |
public override Dictionary<string, object> GetAssociatedData() |
{ |
return _customValues; |
} |
/// <summary> |
/// Override the target folder based on the type. |
/// </summary> |
/// <returns></returns> |
public override string GetTargetFolder() |
{ |
string fileType = this.Request.Form["JT_FileType"]; |
string dcName = this.Request.Form["JT_Dc"]; |
// If it's a custom file type |
if (!string.IsNullOrEmpty(fileType)) |
{ |
ArrayList alDirs = new ArrayList(); |
alDirs.Add(dcName); |
if ((fileType.Equals("Category")) && (!string.IsNullOrEmpty(dcName))) |
{ |
alDirs.Add("Categories"); |
alDirs.Add("images"); |
if (IsNewFileRequest()) |
{ |
if (!EnsureDirectoryStructExists(this.Context, alDirs, true)) |
{ |
jt_Error_Log error = new jt_Error_Log(); |
error.Description = "Directory could not be created"; |
error.Error_Code = -1; |
error.Error_Date = DateTime.Now; |
error.Module_Name = "Upload Handler"; |
error.Filename = "TestHandler.ashx"; |
JtDataContext db = new JtDataContext(); |
db.jt_Error_Logs.InsertOnSubmit(error); |
db.SubmitChanges(); |
} |
return BuildPhysicalDirectory(alDirs, true); |
} |
else |
return BuildPhysicalDirectory(alDirs, true); |
} |
else |
return base.GetTargetFolder(); |
} |
// Otherwise do the default behavior. |
else |
{ |
return base.GetTargetFolder(); |
} |
} |
public override void ProcessStream() |
{ |
if (this.IsFinalFileRequest()) |
{ |
string fileType = this.Request.Form["JT_FileType"]; |
string dcName = this.Request.Form["JT_Dc"]; |
if (!string.IsNullOrEmpty(fileType)) |
{ |
if (fileType.Equals("Category")) |
{ |
string sCategoryId = this.Request.Form["JT_CategoryId"]; |
int categoryId = 0; |
if (int.TryParse(sCategoryId, out categoryId)) |
{ |
JtDataContext db = new JtDataContext(); |
jt_Category cat = (from c in db.jt_Categories |
where c.CategoryId == categoryId |
select c).Single(); |
ArrayList alDirs = new ArrayList(); |
alDirs.Add(dcName); |
alDirs.Add("Categories"); |
alDirs.Add("images"); |
cat.ImageFile = Path.Combine(BuildRelativeDirectory(alDirs, true), this.Request.Params["RadUAG_FileName"]); |
db.SubmitChanges(); |
_customValues = new Dictionary<string, object>(); |
_customValues.Add("JT_FileName", WcfServiceUtils.ResolveServerImgUrl(Path.Combine(BuildRelativeDirectory(alDirs, true), this.Request.Params["RadUAG_FileName"]))); |
} |
} |
} |
base.ProcessStream(); |
} |
else |
{ |
base.ProcessStream(); |
} |
} |
} |
Xaml:
<StackPanel> |
<Image x:Name="imgCategory" MaxHeight="200" MaxWidth="300"> |
</Image> |
<telerik:RadUpload x:Name="rulImage" Grid.Row="4" Grid.ColumnSpan="2" |
IsAutomaticUpload="false" |
OverwriteExistingFiles="True" FileUploaded="rulImage_FileUploaded" |
UploadServiceUrl="{StaticResource UploadServiceUrl}" |
TargetFolder="{StaticResource TargetFolder}" |
IsMultiselect="False" |
/> |
</StackPanel> |
Here's the idea on the SL client side, code-behind:
void CategoryEntry_Loaded(object sender, RoutedEventArgs e) |
{ |
if (!loaded) |
{ |
rulImage.AdditionalPostFields.Add("JT_FileType", "Category"); |
rulImage.AdditionalPostFields.Add("JT_Dc", DcAppContext.GetDcAppContext().DcUsc.DcName); |
rulImage.AdditionalPostFields.Add("JT_CategoryId", _currentData.CategoryId.ToString()); |
} |
loaded = true; |
} |
private void rulImage_FileUploaded(object sender, FileUploadedEventArgs e) |
{ |
string newFile = e.HandlerData.CustomData["JT_FileName"] as string; |
if (!string.IsNullOrEmpty(newFile)) |
{ |
newFile = newFile.Replace("\\\\", "\\"); |
newFile = newFile.Replace("\\", "/"); |
_currentData.ImageFile = newFile; |
System.Windows.Media.Imaging.BitmapImage bmi = new System.Windows.Media.Imaging.BitmapImage(new Uri(newFile, UriKind.Absolute)); |
imgCategory.Source = bmi; |
} |
} |
Do you need any more help on this from Telerik?
Greetings,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Hi,
Where can I find the IsFinalUpload() method? Is it in the Upload handler?
Felix
we removed that method from with the latest release. What is your scenario? Why you need it?
Sincerely yours,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
I want to save all the uploaded files to the database from the Httphandler after all the files are uploaded to the web server and so I want to do it in the last request. In addition, I cannot change the AdditionalPostFields parameter during an Upload Session. For example, I want to change the AdditionalPostFields in an FilesSelected or UploadStarted event but they are not postback to the handler
Thank you
Regards,
Felix
We will consider bringing this method back for the next release.
During the upload session you can pass custom parameters to the handler, but not by using the AdditionalPostFields property. Check these online resources to see how to do it:
Examples:
http://demos.telerik.com/silverlight/#Examples/Upload/Events
http://demos.telerik.com/silverlight/#Examples/Upload/CustomParameters
Help articles:
http://www.telerik.com/help/silverlight/passing_custom_params_to_the_server_side_handler.html
http://www.telerik.com/help/silverlight/returning_custom_data_from_the_handler.html
http://www.telerik.com/help/silverlight/creating_custom_server-side_handler.html
Kind regards,
Valentin.Stoychev
the Telerik team
Check out Telerik Trainer, the state of the art learning tool for Telerik products.
On a side note, would is also be possible to get the source code for the Radupload control? There are actions in the code-behind that we need access to.
Thanks,
Sorry for the delayed reply. Soon you will be contacted by one of our sales representatives who will give you more details about your subscription and source code.
Greetings,
Kiril Stanoev
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>