Home » Asp.netRSS

update datalist in updatepanel after asyncfileupload has uploaded a new file

I want to update an updatepanel after the user has uploaded a photo via the asynfileupload control.

Below is my current code. I also tried setting updatemode="conditional" to "false" and then in code-behind call upnlPhotos.update, but without luck...

Upload photo: <cc1:AsyncFileUpload ID="afuPhoto" runat="server" /><br />

<asp:UpdatePanel ID="upnlPhotos" runat="server">
    <ContentTemplate>


    <asp:DataList ID="dlPhotos" DataSourceID="dsPhotos" DataKeyField="id" RepeatColumns="5" RepeatDirection="Horizontal" GridLines="None" runat="server" >
    <ItemTemplate>
        <img alt="" src='/images/trouwlocatiefotos/thumbs/<%# Eval("locpath")%>' /><br />            
    </ItemTemplate>
    </asp:DataList>

    <asp:SqlDataSource ID="dsPhotos" SelectCommand="SELECT id,locationid,locpath from location_photos lp where locationid=@locationid" ConnectionString="<%$ConnectionStrings:conn1 %>" runat="server">
        <SelectParameters>
            <asp:QueryStringParameter QueryStringField="id" Type="Int32" Name="locationid" />
        </SelectParameters>
    </asp:SqlDataSource>

    </ContentTemplate>
    <Triggers>
        <asp:AsyncPostBackTrigger ControlID="afuPhoto" EventName="UploadedComplete" />
    </Triggers>
</asp:UpdatePanel>   

 

24 Answers Found

 

Answer 1

Peter Smith:
Below is my current  code. I also tried setting  updatemode="conditional" to "false" and then in code-behind  call upnlPhotos.update, but without luck...
 

AsyncFileUpload Control uses an iframe to send the file  to the server, ie it does not use the same async postback mechanism as updatepanel.Try by forcing page postback after file upload  event.

 

Answer 2

You can use UploadedComplete event, in this event you can bind the datalist  again and update  the update panel 

 

Answer 3

In .UploadedComplete event I have this:

dlPhotos.DataBind()
upnlPhotos.Update()

But it still doesnt work.

And I tried it with fileupload control inside and outside the updatepanel.

Other suggestions?


 

Answer 4

Peter Smith:
dlPhotos.DataBind()   upnlPhotos.Update()  


But it still doesnt work.

 

As i said it won't work. You have to do a full page post back or some JS solution like this..

http://forums.asp.net/p/1576992/3975535.aspx#3964776

 

Answer 5

A full postback?!? That is horrible :)

I checked your link, but how would I refresh the datalist using javascript?

Would a normal upload control solve my problem or does that always do a full postback?


 

Answer 6

Hi,

Peter Smith:
I checked your link, but how would I refresh the datalist using javascript?
 

Please check my post in this link:

http://forums.asp.net/p/1609503/4114675.aspx#4114675

 

Answer 7

Hi Jerry,

Thanks. I tried copying what you posted there, but that didnt work for me.

However, I noticed some other unexpected behaviour.

The first time the page loads, the dlPhotos.ItemDataBound method is called. And the message "row_databound" is logged.
When I click the "btnDelete" button, the ItemDataBound is called again. BUT when I click the "btnSetThumbnail" button the ItemDataBound method is NOT called!!

Even though in the itemcommand method I call the same 2 lines for both buttons:
dlPhotos.DataBind()
upnlPhotos.Update()

Why is this happening?

See my code:

        <asp:DataList ID="dlPhotos" DataSourceID="dsPhotos" DataKeyField="id" RepeatColumns="5" RepeatDirection="Horizontal" GridLines="None" runat="server" >
        <ItemStyle VerticalAlign="Top" Width="120" BorderColor="Black" />
        <ItemTemplate>
            <asp:Button ID="btnSetThumbnail" CausesValidation="false" CommandName="setthumb" CommandArgument='<%# string.Format("{0}|{1}",DataBinder.Eval(Container.DataItem, "id"),DataBinder.Eval(Container.DataItem, "locationid"))%>' Text="set as thumb" runat="server" /><br />
            <img alt="" src='/images/trouwlocatiefotos/thumbs/<%# Eval("locpath")%>' /><br />            
            <asp:Button ID="btnDelete" CausesValidation="false" CommandName="deletephoto" CommandArgument='<%# string.Format("{0}|{1}|{2}",DataBinder.Eval(Container.DataItem, "id"),DataBinder.Eval(Container.DataItem, "locationid"),DataBinder.Eval(Container.DataItem, "locpath"))%>' Text="Delete" runat="server" />
        </ItemTemplate>
        </asp:DataList>

        <asp:SqlDataSource ID="dsPhotos" SelectCommand="SELECT id,locationid,locpath from location_photos lp where locationid=@locationid" ConnectionString="<%$ConnectionStrings:conn1 %>" runat="server">
            <SelectParameters>
                <asp:QueryStringParameter QueryStringField="id" Type="Int32" Name="locationid" />
            </SelectParameters>
        </asp:SqlDataSource>

        </ContentTemplate>
        </asp:UpdatePanel>          



Strange thing:
   Protected Sub dlPhotos_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) Handles dlPhotos.ItemCommand
        Dim cmds() As String = e.CommandArgument.ToString.Split("|")
        Dim photoid, locationid As Integer
        Int32.TryParse(cmds(0), photoid)
        Int32.TryParse(cmds(1), locationid)

        If e.CommandName = "deletephoto" Then
            'delete photo from database
            Dim TAphotos As New mediaTableAdapters.location_photosTableAdapter
            TAphotos.DeletePhoto(photoid, locationid)
            dlPhotos.DataBind()
            upnlPhotos.Update()
        ElseIf e.CommandName = "setthumb" Then
            If locationsDAL.SetLocationThumbnail(locationid, photoid) Then
                dlPhotos.DataBind()
                upnlPhotos.Update()
            End If
        End If
    End Sub
    
    Protected Sub dlPhotos_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) Handles dlPhotos.ItemDataBound
        'if the thumbId of the image is the same as thumbid of the location
        LogError("row_databound", "")
        If e.Item.DataItem("id").ToString <> "" And e.Item.DataItem("id").ToString = GetFieldFromSession(Session, "//root/data/location/thumbid") Then
            e.Item.BackColor = Color.Aqua
        End If

    End Sub  


 

Answer 8

What I've done is use a label as a flag indicating that the update panel needs a refresh

As soon as a file is uploaded, the flag is changed so when the interval passes triggers a partial update.

the __doPostback forces the event handler server side to databind the list. It will be clearer in code.

The marckup and javascript:

<%@ Page Title="" Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false"
    CodeFile="UpdateDatalistInUpdatepanel.aspx.vb" Inherits="AsyncUpload_UpdateDatalistInUpdatepanel" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit"
    TagPrefix="asp" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="Server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Scripts>
            <asp:ScriptReference Path="~/Scripts/jquery-1.4.2.min.js" />
        </Scripts>
    </asp:ScriptManager>
    <h2>
        http://forums.asp.net/p/1608333/4114922.aspx</h2>
    <p>
        <asp:AsyncFileUpload ID="afuPhoto" runat="server" ClientIDMode="AutoID"
            OnClientUploadComplete="uploadComplete" />
        <span style="displaynone">
            <asp:Label ID="flag" runat="server" Text="Waiting" ClientIDMode="Static" />
        </span>
        <br />
        <asp:UpdatePanel ID="upnlPhotos" runat="server" OnLoad="upnlPhotos_Load">
            <ContentTemplate>
                <asp:DataList ID="dlPhotos" DataSourceID="dsPhotos" DataKeyField="id" RepeatColumns="5"
                    RepeatDirection="Horizontal" GridLines="None" runat="server">
                    <ItemTemplate>
                        <img alt="" src='PicHandler.ashx?i=<%# Eval("Id")%>' width="160" /><br />
                    </ItemTemplate>
                </asp:DataList>
                <asp:EntityDataSource ID="dsPhotos" runat="server" ConnectionString="name=GoGetter"
                    DefaultContainerName="GoGetter" EnableDelete="True" EnableFlattening="False"
                    EnableInsert="True" EnableUpdate="True" EntitySetName="Blobs">
                </asp:EntityDataSource>
            </ContentTemplate>
        </asp:UpdatePanel>
        <script type="text/javascript">
            Sys.Application.add_init(application_init);

            function application_init() {


                var prm = Sys.WebForms.PageRequestManager.getInstance();

                prm.add_pageLoaded(prm_pageLoaded);

            }

            function prm_pageLoaded() {

                $('#flag').text('Waiting');
            }

            function uploadComplete(sender) {
                $('#flag').text('Refresh');
            }


            $(document).ready(
                              setInterval(function () {
                                  var f = $('#flag').text();
                                  if (f != 'Waiting') { __doPostBack('upnlPhotos'''); }
                              }, 2000)
                         );
        </script>
    </p>
</asp:Content>

And the code behind:

Imports dal

Partial Class AsyncUpload_UpdateDatalistInUpdatepanel
    Inherits System.Web.UI.Page

    Protected Sub afuPhoto_UploadedComplete(ByVal sender As ObjectByVal e As AjaxControlToolkit.AsyncFileUploadEventArgsHandles afuPhoto.UploadedComplete
        If afuPhoto.HasFile Then
            Using w As New GoGetter
                Dim o As Blob = New Blob With {.Pic = afuPhoto.FileBytes}
                w.AddToBlobs(o)
                w.SaveChanges(Data.Objects.SaveOptions.AcceptAllChangesAfterSave)
                afuPhoto.ClearAllFilesFromPersistedStore()
                flag.Text = "Refresh"
            End Using
        End If
    End Sub



    Protected Sub upnlPhotos_Load(ByVal sender As ObjectByVal e As System.EventArgs)
        dlPhotos.DataBind()
        afuPhoto.ClearAllFilesFromPersistedStore()

    End Sub
End Class

I used entities to retrieve and save data
There is also a simple handler to serve the images, not optimized, but if the code helps, here it is
<%@ WebHandler Language="VB" Class="PicHandler" %>

Imports System
Imports System.Web
Imports dal

Public Class PicHandler : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContextImplements IHttpHandler.ProcessRequest
        Dim data As Byte()
        Using w As New GoGetter
            
            Dim i As Integer = _
                CInt(context.Request.QueryString("i"))
            
            
            data = w.Blobs.FirstOrDefault(Function(x) x.Id = i).Pic
            
            
        End Using
        
        
        context.Response.ContentType = "image/jpeg"
        context.Response.BinaryWrite(data)
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

End Class

I hope I make sense!
 

Answer 9

Cool. It now (somewhyat) works.

what it does: it refreshes the datalist! :)

BUT it also seems that the method:
Protected Sub afuPhoto_UploadedComplete(ByVal sender As Object, ByVal e As AjaxControlToolkit.AsyncFileUploadEventArgs) Handles afuPhoto.UploadedComplete

is called twice! resulting in the same image being placed in DB twice...why is the upload called twice?



I have copied some parts of your code:

<script type="text/javascript">
    Sys.Application.add_init(application_init);
    function application_init() {
        var prm = Sys.WebForms.PageRequestManager.getInstance();
        prm.add_pageLoaded(prm_pageLoaded);
    }

    function prm_pageLoaded() {
        $('#flag').text('Waiting');
    }

    function uploadComplete(sender) {
        $('#flag').text('Refresh');
    }

    $(document).ready(
                        setInterval(function () {
                            var f = $('#flag').text();
                            if (f != 'Waiting') { __doPostBack('upnlPhotos', ''); }
                        }, 2000)
                    );
</script>

<cc1:AsyncFileUpload ID="afuPhoto" OnClientUploadComplete="uploadComplete" runat="server" /><br />
        <span style="display: none">
            <asp:Label ID="flag" runat="server" Text="Waiting" ClientIDMode="Static" />
        </span>

    Protected Sub upnlPhotos_Load(ByVal sender As Object, ByVal e As System.EventArgs)
        dlPhotos.DataBind()
    End Sub


What does this "setInterval" do? Will it fail if uploading takes longer than 2 seconds?





 

Answer 10

setInterval is a standard javascript function, see http://www.w3schools.com/js/js_timing.asp

i think it would fail if it takes more than two sec to save the file after uploading. The flag is set on upload complete

make sure that you handle the load event of the update panel server side, yes?

the image is saved twice? weird! if you don't handle the update panel load event, the the __doPostback would cause a full page update.

That would possibly cause the UploadComplete event fire twice I think. Please make sure that this is not the case.

By the way, I had fun with this puzzle. Let me know how it goes.

P.S. I also noticed that the asyncfileupload control behaves bad when you don't set it's ClientIDMode to AutoId

 

 

Answer 11

Ok, that method was not hit,
I now have this: <asp:UpdatePanel ID="upnlPhotos" OnLoad="upnlPhotos_Load" runat="server">
(forgot to add the bold part).
I also removed the UpdateMode="Conditional" from the updatepanel.

Now the Protected Sub upnlPhotos_Load(ByVal sender As Object, ByVal e As System.EventArgs) method is hit.

But still the image is uploaded twice.


For complete overview of current status:

current script:
<script type="text/javascript">
    Sys.Application.add_init(application_init);
    function application_init() {
        var prm = Sys.WebForms.PageRequestManager.getInstance();
        prm.add_pageLoaded(prm_pageLoaded);
    }

    function prm_pageLoaded() {
        $('#flag').text('Waiting');        
    }

    function uploadComplete(sender) {
        $('#flag').text('Refresh');
    }

    $(document).ready(
                        setInterval(function () {
                            var f = $('#flag').text();
                            if (f != 'Waiting') { __doPostBack('upnlPhotos', ''); }
                        }, 2000)
                    );
</script>



        <asp:UpdatePanel ID="upnlPhotos" OnLoad="upnlPhotos_Load" runat="server">
        <ContentTemplate>

        <asp:Label ID="lblPhotostatus" runat="server" />

        Upload photo: <cc1:AsyncFileUpload ID="afuPhoto" OnClientUploadComplete="uploadComplete" runat="server" /><br />
        <span style="display: none">
            <asp:Label ID="flag" runat="server" Text="Waiting" ClientIDMode="Static" />
        </span>


        <asp:DataList ID="dlPhotos" DataSourceID="dsPhotos" DataKeyField="id" RepeatColumns="5" RepeatDirection="Horizontal" GridLines="None" runat="server" >
        <ItemStyle VerticalAlign="Top" Width="120" BorderColor="Black" />
        <ItemTemplate>
            <asp:Button ID="btnSetThumbnail" CausesValidation="false" CommandName="setthumb" CommandArgument='<%# string.Format("{0}|{1}",DataBinder.Eval(Container.DataItem, "id"),DataBinder.Eval(Container.DataItem, "locationid"))%>' Text="set thumb" runat="server" /><br />
            <img alt="" src='/images/thumbs/<%# Eval("locpath")%>' /><br />            
            <asp:Button ID="btnDelete" CausesValidation="false" CommandName="deletephoto" CommandArgument='<%# string.Format("{0}|{1}|{2}",DataBinder.Eval(Container.DataItem, "id"),DataBinder.Eval(Container.DataItem, "locationid"),DataBinder.Eval(Container.DataItem, "locpath"))%>' Text="Delete" runat="server" />
        </ItemTemplate>
        </asp:DataList>

        <asp:SqlDataSource ID="dsPhotos" SelectCommand="SELECT id,locationid,locpath from location_photos lp where locationid=@locationid" ConnectionString="<%$ConnectionStrings:conn1 %>" runat="server">
            <SelectParameters>
                <asp:QueryStringParameter QueryStringField="id" Type="Int32" Name="locationid" />
            </SelectParameters>
        </asp:SqlDataSource>

        </ContentTemplate>
        </asp:UpdatePanel>



hmmm and having a preset interval at 2 seconds is a bit dodgy isnt it? I mean: what if a user has a slower connection? This is not foolproof is it? Is this however the best way to handle async uploads? If you have better suggestions Im open to that as well :)

 

Answer 12

You  have a point about the two seconds, it is not foolproof. It is a workaround. 

I'll have another look at it later, maybe a not so elegant solution using iframes?

I'm thinking of two scenarios

1. an async file upload and a button inside the update panel

2. a pure javascript solution with no update panel, using jTemplates to display data



 

Answer 13

Well Im not sure about the pros and cons of both scenario's with regard to userfriendliness and 'foolproofability' ;)

The thing is: the datalist has to support some other actions as well:
1. I want to be able to delete a single image by clicking a delete button
2. I want to be able to indicate which image in the datalist will be the thumbnail image
3. (in the future) able to add a text with an image

4. no full pageloads
5. foolproof in the sense that its not dependent on bandwidth speed of user


If you hear these requirements, perhaps you can determine what is the best scenario?

Hopefully this puzzle remains interesting for you ;)

Thanks again!

 

Answer 14

Hi mitsbits,

Have you had the time to look at this?

Thanks!



 

Answer 15

yeap but no luck yet. the only good result I had is use session variable to check and  eliminate the second insert.

As far as updates and deletes are concerned there seems to be no problem.

I have to get back to you in a couple of days. I want to use the same functionality in a project of mine, so I won't give up yet.

Maybe we should loose the update panel all together?

 

Answer 16

Glad to see you're still puzzling :)

Really wondering what the outcome will be, because I just KNOW a lot of people would love this feature. As you might have seen, this thread has been marked as excellent by I think a forum administrator :)

Anyways...loose the updatepanel...

I dont HAVE to have that panel, but Im wondering if the user friendliness can be maintained. I mean: after a user uploads an image, he would want to see it in the total overview right?
Also, when he deletes an image, he would have to see that as well.

They way to achieve it (with or without updatepanel) is, to me, less important than the result for the user. Do you agree?


 

Answer 17

It is always the outcome that matters.

I'm not talking about full page postbacks.

I was reading about this http://www.borismoore.com/2010/09/introducing-jquery-templates-1-first.html and this http://weblogs.asp.net/joelvarty/archive/2009/12/04/the-jtemplates-plugin-for-jquery-keep-inline-templates-from-being-misinterpreted.aspx I don't know if this is the way to do it. 

This kind of functionality on the other hand is all over the net.

I have never used jTemplates or databindibg client side, so I saving my strengths and looking for at least a 4-5 hour opening in my schedule to dive into it, but man time is scarce.

 

Answer 18

Hi there, I have a working solution without an update panel. 

First you will need the script from http://jtemplates.tpython.com/ and also a reference to jQuery.

These scripts as well as the script manager I included in the master page. The script needs a template. I named the template BlobTable.htm and placed it in a folder called templates. This is the code.

<table>
    <thead>
        <tr>
            <th>
                Id
            </th>
            <th>
                Image
            </th>
            <th>
                Command
            </th>
        </tr>
    </thead>
    <tbody>
        {#foreach $T.d as blob}
        <tr>
            <td>
                {$T.blob.Id}
            </td>
            <td>
                <img src='handlers/PicHandler.ashx?i={$T.blob.Id}' width="120" />
            </td>
            <td>
                <a id='bt' href="#" onclick='return DeleteBlob({$T.blob.Id});'>Delete</a>
            </td>
        </tr>
        {#/for}
    </tbody>
</table>



So far so good. The I created a web service to handle retrieving and deleting of data named DalService.asmx. GoGetter is the name of my Entity Data Context. Here it is:

Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports dal

' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
<System.Web.Script.Services.ScriptService()> _
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class DalService
    Inherits System.Web.Services.WebService

    <WebMethod()> _
    Public Function DeleteBlob(ByVal theId As IntegerAs Integer
        Dim result As Integer = 0
        Using w As New GoGetter
            w.Blobs.DeleteObject(w.Blobs.FirstOrDefault(Function(x) x.Id = theId))
            result = w.SaveChanges(Data.Objects.SaveOptions.AcceptAllChangesAfterSave)
        End Using
        Return result
    End Function
    <WebMethod()> _
    Public Function GetBlobs() As Blob()
        Dim result As New List(Of Blob)
        Using w As New GoGetter


            Dim q = _
                From b As Blob _
                In w.Blobs _
                Select b.Id

            For Each i As Integer In q.ToList
                result.Add(New Blob With {.Id = i, .Binary = Nothing})
            Next
        End Using
        result.TrimExcess()
        Return result.ToArray
    End Function
End Class

Now the fun part. The default.aspx has a async file upload and a p with the id "Container". Inside the container the data from the web service will be rendered. First the code behind:

Imports dal

Partial Class _Default
    Inherits System.Web.UI.Page

    Protected Sub afuPhoto_UploadedComplete(ByVal sender As Object, _
                                            ByVal e As AjaxControlToolkit.AsyncFileUploadEventArgs) _
                                            Handles afuPhoto.UploadedComplete
        If afuPhoto.HasFile _
            AndAlso e.state = AjaxControlToolkit.AsyncFileUploadState.Success Then
            Using w As New GoGetter
                Dim o As Blob = New Blob With {.Binary = afuPhoto.FileBytes}
                w.AddToBlobs(o)
                w.SaveChanges(Data.Objects.SaveOptions.AcceptAllChangesAfterSave)
                afuPhoto.ClearAllFilesFromPersistedStore()
            End Using
        End If
    End Sub
End Class

Ok. here is the markup of default.aspx. Notice the function ShowData() that retrieves data from the web service and then calls ApplyTemplate() to render the template with the data. DeleteBlob() clears an image from the database and then calls ShowData() to refresh the page.

    <script type="text/javascript">

        function uploadComplete(sender) {
            setTimeout("ShowData()", 1000);
        }

        function ApplyTemplate(result) {
            $('#Container').setTemplateURL('<%= Page.ResolveUrl("~/templates/BlobTable.htm")  %>',
                                 null, { filter_data: false });
            $('#Container').processTemplate(result);
        }

        function ShowData() {
            $.ajax({
                type: "POST",
                url: '<%= Page.ResolveUrl("~/services/DalService.asmx/GetBlobs")  %>',
                data: "{}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (result) {
                    ApplyTemplate(result);
                }
            });
        }

        function DeleteBlob(theId) {
            $.ajax({
                type: "POST",
                url: '<%= Page.ResolveUrl("~/services/DalService.asmx/DeleteBlob")  %>',
                data: "{theId: '" + theId + "'}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
               
            });
            ShowData();
            return false;
        }
    </script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
        http://forums.asp.net/t/1608333.aspx
    </h2>
    <p>
        <label for='<%= afuPhoto.ClientId %>'>
            Select a file:
        </label>
        <ajaxToolkit:AsyncFileUpload ID="afuPhoto" runat="server" ClientIDMode="AutoID" OnClientUploadComplete="uploadComplete" />
    </p>
    <p id="Container">
    </p>
    <script type="text/javascript">
        $(document).ready(function () {
            ShowData();
        });
    </script>
</asp:Content>

This worked for me. I need to get more work done with templates. I noticed that things like <%= Page.ResolveUrl("~/...") %> do not work, not with this script anyway, and it makes sense.

There is an issue clearing the text from the async file upload after the upload completes. 

Give it a try and we see how it works.

 

Answer 19

Ok, this looks promising! :)

I did a couple of things:
- included jtemplates and jquery
- created dalservice.asmx
- created a page test.aspx


Now my questions:

1. what does this line (dont see other PicHandler.ashx details in your code):
<img src='handlers/PicHandler.ashx?i={$T.blob.Id}' width="120" />

You make use of a Blob class, my guess is thats because you want to do some quick testing.
In your webservice you have:
    <WebMethod()> _
    Public Function GetBlobs() As Blob()
    
2. What is Blob?
3. What class would I need to use here...I want to retreive images from disk based on their physical pathname which I retreive from DB, is that still possible?


in your code behind:

Dim o As Blob = New Blob With {.Binary = afuPhoto.FileBytes}

4. Here I want to use: Dim imgOriginal As Image = System.Drawing.Image.FromStream(afuPhoto.PostedFile.InputStream), because I need to do some resizing work before I save the image to disk. Would that still work instead of afuPhoto.FileBytes?

5. the datalist would be no longer necessary correct?

 

Answer 20

Peter Smith:
PicHandler.ashx

You will find a handler serving the pictures in a previous thread in this post, it is the same and really basic, that is why I didn't include it here

Peter Smith:
Blob
.

It is the class name generated by the Entity framework, the name of my db table is Blobs, with two fields Id int & Binary image.

Blob stands for Binary Large Object, seemed appropriate name for the situation

Peter Smith:
3. What class would I need to use here...I want to retreive images from disk based on their physical pathname which I retreive from DB, is that still possible?
.

Use what you like. Retrieving the image from the corresponding folder I guess I would do it in the PicHandler, meaning finding the path to the file and serving the image based on the Id.

When I instantiated a blob, and the calling SaveChanges is the same as saving the image in a folder and inserting a row in the database with the details of the picture. I think this is where you can resize your image, either saving it and manipulating it or creating an image from byte array and dealing with it with GDI+

Peter Smith:
5. the datalist would be no longer necessary correct?

Yeap, no need for it.

Let me know how it went.


P.S. I'll provide you later on with a version without using Entity framework. I'll use dataset, as I should have in the first place to make things clear.

 

Answer 21

I see..I hope you're not doing the dataset solution for me, because if you're not I'd rather wait for that. The Blob field is bit too abstract for me $
And the dataset solution would also be exactly how I would implement it :) (i use those a lot btw, but they are not really optimized for performance right?)

Also im guessing "processTemplate" is a native method of jtemplates?


Thanks a bunch again for your time!

Also, is this code what you'll be using yourself in your own project? :)

 

Answer 22

Hi, here is a dataset version. 

The table has two fields Id int autonumber & Picture nvarchar. The dataset is calles BlobData, the table Blobs.

There is also a method of the table adapter, returning the Picture string based in the Id.

Changes in the files are:

DalService
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class DalService
    Inherits System.Web.Services.WebService


    Public Class Blob
        Public Property Id As Integer
        Public Property Picture As String
    End Class



    <WebMethod()> _
    Public Function DeleteBlob(ByVal theId As IntegerAs Integer
        Dim result As Integer = 0
        Using w As New BlobDataTableAdapters.BlobsTableAdapter
            result = w.Delete(theId)
        End Using
        Return result
    End Function
    <WebMethod()> _
    Public Function GetBlobs() As Blob()
        Dim result As New List(Of Blob)
        Using w As New BlobDataTableAdapters.BlobsTableAdapter


            For Each r As BlobData.BlobsRow In w.GetData
                Dim b As New Blob With {.Id = r.Id}
                result.Add(b)
            Next

        End Using
        result.TrimExcess()
        Return result.ToArray
    End Function
End Class


PicHandler
<%@ WebHandler Language="VB" Class="PicHandler" %>
 
Imports System
Imports System.Web
Imports dal
 
Public Class PicHandler : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContextImplements IHttpHandler.ProcessRequest
        Dim data As Byte()
  
            
        Dim i As Integer = _
            CInt(context.Request.QueryString("i"))
            
        Dim fName As String = String.Empty
            
        Using w As New BlobDataTableAdapters.BlobsTableAdapter

            fName = w.GetPicture(i)
        End Using
            
            
            
        data = My.Computer.FileSystem.ReadAllBytes(context.Server.MapPath("~/images/" & fName))
            
            
       
        
        
        context.Response.ContentType = "image/jpeg"
        context.Response.BinaryWrite(data)
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property
 
End Class

Default.aspx.vb
Partial Class _Default
    Inherits System.Web.UI.Page

    Protected Sub afuPhoto_UploadedComplete(ByVal sender As Object, _
                                            ByVal e As AjaxControlToolkit.AsyncFileUploadEventArgs) _
                                            Handles afuPhoto.UploadedComplete
        If afuPhoto.HasFile _
            AndAlso e.state = AjaxControlToolkit.AsyncFileUploadState.Success Then
            Dim dir As New IO.DirectoryInfo(Server.MapPath("~/images"))
            Dim fName As String = e.filename
            If My.Computer.FileSystem.FileExists(dir.FullName & "/" & fName) Then
                fName = Now.Ticks.ToString & e.filename
            End If
            afuPhoto.SaveAs(dir.FullName & "/" & fName)

            Using w As New BlobDataTableAdapters.BlobsTableAdapter
                w.Insert(fName)
            End Using

        End If
    End Sub
End Class


The rest of the code is the same.

I'll be using the same thing more or less.

I need in place editing functionality for one thing and I will study a bit more templating scripts.

Have fun! 

 

Answer 23

Dude....1 word...WOW! This works AWE-SOME!!! :-D

Dont know if you keep your own blog, but if you do, definitely post it there..I'm betting loads of people can use this code!

Few more questions though (I think they are small):

I want to pass a parameter to your webmethod, so I changed it from: Public Function GetBlobs() As Blob()

to: Public Function GetBlobs(ByVal locationId As Integer) As Blob()

Now in javascript, you call this webmethod:
function ShowData() {
            $.ajax({
                type: "POST",
                url: '<%= Page.ResolveUrl("~/DalService.asmx/GetBlobs")  %>',
                data: "{}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (result) {
                    ApplyTemplate(result);
                }
            });
        }

1. How can I dynamically add a parameter value to the GetBlobs method? Particularly, how would I call it: ~/DalService.asmx/GetBlobs(545) or ~/DalService.asmx/GetBlobs/545 or....


Also in your template you have:
<a id='bt' href="#" onclick='return DeleteBlob({$T.blob.Id});'>Delete</a>


2. Now, normally I worked with the asp.net buttons, where it is easy to show a confirmation dialog, like: 'are you sure you want to delete this image?'. How would I do that now?


3. I think I have a tip for you (even though small one). In your code you have:

For Each r As BlobData.BlobsRow In w.GetData
                Dim b As New Blob With {.Id = r.Id}
                result.Add(b)
            Next

I thought it was the best practice from a performance perspective not to create new variables in loops, since they will get recreated over and over. Particularly with large datasets this can cause issues.
Hopefully Im right about that, so at least I have contributed SOMETHING to your awesome code ;)

Thanks again!

Pete


 

Answer 24

Peter Smith:
Dude....1 word...WOW! This works AWE-SOME!!! :-D

Thanx! Do you see me blushing? I'm glad I could help.

Peter Smith:
I want to pass a parameter to your webmethod, so I changed it from: Public Function GetBlobs() As Blob()

to: Public Function GetBlobs(ByVal locationId As Integer) As Blob()

Now in javascript, you call this webmethod:
function ShowData() {
            $.ajax({
                type: "POST",
                url: '<%= Page.ResolveUrl("~/DalService.asmx/GetBlobs")  %>',
                data: "{}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (result) {
                    ApplyTemplate(result);
                }
            });
        }

You have to do the same thing as the DeleteBlob function. Let's say you have a textbox called txtLocation where users input the location id. The function should look like this:


        function ShowData() {

            var loc = $('#' + '<%= txtLocation.ClientId  %>').val();

            $.ajax({
                type: "POST",
                url: '<%= Page.ResolveUrl("~/DalService.asmx/GetBlobs")  %>',
                data: "{locationId:'" + loc + "'}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (result) {
                    ApplyTemplate(result);
                }
            });       }



 

Peter Smith:
2. Now, normally I worked with the asp.net buttons, where it is easy to show a confirmation dialog, like: 'are you sure you want to delete this image?'. How would I do that now?

For this you have to modify the DeleteBlob function:

        function DeleteBlob(theId) {

            if (confirm("Really delete this picture?")) {
                $.ajax({
                    type: "POST",
                    url: '<%= Page.ResolveUrl("~/services/DalService.asmx/DeleteBlob")  %>',
                    data: "{theId: '" + theId + "'}",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json"

                });

                ShowData();
                return false;

            }
        }


And of course you are on the spot with you third remark!

Have a nice weekend Peter.

 
 
 

<< Previous      Next >>


Microsoft   |   Windows   |   Visual Studio   |   Follow us on Twitter