Search code examples
c#asp.net-mvchttp-redirectflickr

How to execute certain part of code just once in MVC5 using C#?


I have a view where user chooses a photo from his/her computer and uploads it to Flickr. The point is that once the button is clicked, it redirects to Flickr which asks for authorization, and once authorization process is finished it redirects back to that action method. Below you can see some code to make it more clear.

Test.cshtml:

@using (Html.BeginForm("UploadToFlickr", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <fieldset>
        <input type="file" name="file" />
        <input type="submit" value="Upload!" />
    </fieldset>
}

HomeController.cs:

public class HomeController : Controller
{
        public static string tmpFilePath, filename, path;
        // some other methods...

        public ActionResult UploadToFlickr(HttpPostedFileBase file, FormCollection form)
        {
            tmpFilePath = Server.MapPath("~/App_Data/Uploads/Pictures");

            if (file == null || file.ContentLength == 0)
            {
                return RedirectToAction("Index");
            }

            filename = Path.GetFileName(file.FileName);
            path = Path.Combine(tmpFilePath, filename);

            if (System.IO.File.Exists(path))
            {
                System.IO.File.Delete(path);
            }

            file.SaveAs(path);

            if (Request.QueryString["oauth_verifier"] != null && Session["RequestToken"] != null)
            {
                // Flickr relevant code...

                string photoId = flickr.UploadPicture(path, "Test picture");
            }
            else
            {
                // Flickr relevant code...

                string url = flickr.OAuthCalculateAuthorizationUrl(token.Token, AuthLevel.Write);

                Response.Redirect(url);
            }

            return View("Test");
        }

So the point is that, I have already defined tmpFilePath, filename and path variables as static, as you can see. When I click the upload button, at at first it calls theUploadToFlickr method, which executes the initial lines of code, and then enters into else, which redirects the app to Flickr authorization, then when I click authorize, it again generates a URL that includes the UploadToFlickr method, which call that method again, but this time the file parameter is null, and it enters into the part return RedirectToAction("Index");. Is there any way, how can I solve this? I need the part until the if case to be executed just once, only when the button is clicked. Not the second time when I'm redirected from Flickr.


Solution

  • The callback is most likely using an HTTP GET rather than an HTTP POST. Split your actions into two methods and decorate the one you post to with [HttpPost] and the callback method with [HttpGet]. The [HttpPost] method should only be called when the user hits the upload button (since the FormMethod is set to Post), so that method should only be responsible for validating the file they uploaded and passing it along to Flickr. After Flickr has done it's thing, if it is calling back to your app, it should call the [HttpGet] method, where you redirect or do whatever else you want to do. I'm not familiar with the Flickr API but this should get you close.

    Keep in mind that uploading your image and getting a callback from Flickr are two completely separate requests to your application. You need to determine what to do based on the HTTP request method, provided parameters, etc. for both unique requests.

    public class HomeController : Controller
    {
        public static string tmpFilePath, filename, path;
        // some other methods...
    
        [HttpGet]
        public ActionResult UploadToFlickr()
        {
            // This method will probably get called back by Flickr
    
            return RedirectToAction("Index");
        }
    
        [HttpPost]
        public ActionResult UploadToFlickr(HttpPostedFileBase file, FormCollection form)
        {
            // This method will only be called when the user clicks the upload button
    
            tmpFilePath = Server.MapPath("~/App_Data/Uploads/Pictures");
    
            if (file == null || file.ContentLength == 0)
            {
                // No file was provided...show validation errors or something
            }
    
            filename = Path.GetFileName(file.FileName);
            path = Path.Combine(tmpFilePath, filename);
    
            if (System.IO.File.Exists(path))
            {
                System.IO.File.Delete(path);
            }
    
            file.SaveAs(path);
    
            if (Request.QueryString["oauth_verifier"] != null && Session["RequestToken"] != null)
            {
                // Flickr relevant code...
    
                string photoId = flickr.UploadPicture(path, "Test picture");
            }
            else
            {
                // Flickr relevant code...
    
                string url = flickr.OAuthCalculateAuthorizationUrl(token.Token, AuthLevel.Write);
    
                Response.Redirect(url);
            }
    
            return View("Test");
        }
    }