Uploading files

Could you simply call the built in Create method for that table and specify the filename and the order ID to create it? Does it have to be a custom method? I didn't see the filename sample. Was that in the UploadFiles example application? Also all of the files get dropped into a single folder. Is there a way to create a folder for an order and drop the files in that location. The reason I ask is that if a user happens to upload a file with the same name it simply overrides the old file with the new one with no warning. My users will definitely have issues with this.

Josh

Could you simply call the built in Create method for that table and specify the filename and the order ID to create it?

Yes, this would work.

I didn't see the filename sample. Was that in the UploadFiles example application?

I meant theupload file section from the invoke custom method documentation. It shows how to return the URL of the uploaded file which can be later used for other purposes.

Is there a way to create a folder for an order and drop the files in that location.

Yes, you can do that. You have full control over where the file gets stored. For example you can add a parameter and pass the current OrderID.

[HttpPost]
public IActionResult UploadFiles(IEnumerable<IFormFile> files, int orderId)
{
    // Combine the orderId with the WebRootPath so files are stored per orderId
    var dir = Path.Combine(hostingEnvironment.WebRootPath, orderId.ToString());
    // Create the directory if it doesn't exist
    Directory.CreateDirectory(dir);

    var result = files.Select(file => {
        // Save the files in the directory
        var path = Path.Combine(dir, file.FileName);

        using (var stream = new FileStream(path, FileMode.Create))
        {
            // Save the file
            file.CopyTo(stream);

            var request = HttpContext.Request;

            // Create the URL for the uploaded file - not that orderId is part of the URL
            var url =  $"{request.Scheme}://{request.Host.Value}/{orderId}/{file.FileName}";

            // Return the FileName and Url
            return new {
                FileName = file.FileName,
                Url = url
            };
        }
    }).ToList();

    // Return the file names and URL of the uploaded files
    return Json(new { value = result }, new JsonSerializerSettings() { 
        ContractResolver = new DefaultContractResolver() 
    });
}

That does work for uploading the files and creating the directory structure. It is giving me an error when it is trying to create the record for the attachment in the DB. I am storing 3 columns, the related OrderId, the FileName, and the Url. I added OrderId so that all 3 items needed where returned values.

Here is the error that is showing.

It shows no payload when looking at the Header instead of the Response.

The custom method returns an array of files. The createOrderAttachment method however accepts a single item. Passing an array as the argument will not work.

If you want to support multiple file uploads it would be easier to just insert the records from the UploadFiles method itself.

Good to know. Is this what you mean by inserting the data in the method? Also is there already a database connection created I can call that was setup when I attached the database to the app as a datasource?

    using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting; 
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Data.SqlClient;

namespace UploadFiles.Controllers
{
    
    [Route("upload")]
    public partial class UploadController : Controller
    {

        private readonly IHostingEnvironment hostingEnvironment;

    public UploadController(IHostingEnvironment hostingEnvironment)
        {
        this.hostingEnvironment = hostingEnvironment;

        }   
        [HttpPost]
public IActionResult UploadFiles(IEnumerable<IFormFile> files, int orderId)
{
    // Combine the orderId with the WebRootPath so files are stored per orderId
    var dir = Path.Combine(hostingEnvironment.WebRootPath, orderId.ToString());
    // Create the directory if it doesn't exist
    Directory.CreateDirectory(dir);

    var result = files.Select(file => {
        // Save the files in the directory
        var path = Path.Combine(dir, file.FileName);

        using (var stream = new FileStream(path, FileMode.Create))
        {
            // Save the file
            file.CopyTo(stream);

            var request = HttpContext.Request;

            // Create the URL for the uploaded file - not that orderId is part of the URL
            var url =  $"{request.Scheme}://{request.Host.Value}/{orderId}/{file.FileName}";

            // Return the FileName and Url
            return new {
                FileName = file.FileName,
                Url = url,
                OrderId = orderId
            };
        }
    }).ToList();


            SqlConnection conn = new SqlConnection("Data source=localhost; Database=Northwind;User Id=sa;Password=!QAZxsw2");
            conn.Open();
            SqlCommand cmd = new SqlCommand("insert into dbo.OrderAttachments values(OrderId,FileName,Url);", conn);
            cmd.ExecuteNonQuery();
            conn.Close();


            // Return the file names and URL of the uploaded files
            return Json(new { value = result }, new JsonSerializerSettings() { 
        ContractResolver = new DefaultContractResolver() 
    });
        }

Also is there already a database connection created I can call that was setup when I attached the database to the app as a datasource?

Radzen doesn't keep any open connections to the database. However you can inject the EF context that has been created for your data source so you don't need to write SQL and embed the connection string in your code. Here is how this is done (step 4):

[Route("api/[controller]/[action]")]
public class ServerMethodsController : Controller
{
    private NorthwindContext northwind;

    public ServerMethodsController(NorthwindContext context)
    {
        this.northwind = context;
    }
}

This is obviously beyond me to a point. I feel like I have something out of order. I'm not sure how to get the result values assigned to the fields to insert.

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting; 
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Data.SqlClient;
using FunTimes.Models.Northwind;
using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication;

namespace UploadFiles.Controllers
{

    [Route("upload")]
    public partial class UploadController : Controller
    {

        private readonly IHostingEnvironment hostingEnvironment;

        public UploadController(IHostingEnvironment hostingEnvironment)
        {
            this.hostingEnvironment = hostingEnvironment;

        }


        [HttpPost]
        public IActionResult UploadFiles(IEnumerable<IFormFile> files, int orderId)
        {
            // Combine the orderId with the WebRootPath so files are stored per orderId
            var dir = Path.Combine(hostingEnvironment.WebRootPath, orderId.ToString());
            // Create the directory if it doesn't exist
            Directory.CreateDirectory(dir);

            var result = files.Select(file =>
            {
                // Save the files in the directory
                var path = Path.Combine(dir, file.FileName);

                using (var stream = new FileStream(path, FileMode.Create))
                {
                    // Save the file
                    file.CopyTo(stream);

                    var request = HttpContext.Request;

                    // Create the URL for the uploaded file - not that orderId is part of the URL
                    var url = $"{request.Scheme}://{request.Host.Value}/{orderId}/{file.FileName}";

                    // Return the FileName and Url
                    return new
                    {
                        FileName = file.FileName,
                        Url = url,
                        OrderId = orderId
                    };


                }
            }).ToList();

            // Return the file names and URL of the uploaded files
            return Json(new { value = result }, new JsonSerializerSettings()
            {
                ContractResolver = new DefaultContractResolver()
            });

        }

        // Connect to Northwind to store Order Attachment Record details
        private FunTimes.Data.NorthwindContext northwind;

        public UploadController(FunTimes.Data.NorthwindContext context)
        {
            this.northwind = context;

            var t = new OrderAttachment
            {

                FileName = ,
                Url = ,
                OrderId = 
            };

            context.OrderAttachments.Add(t);
            context.SaveChanges();
        }

    }
}

You have to inject the context as a second constructor parameter.

        private readonly IHostingEnvironment hostingEnvironment;
        private NorthwindContext context;

        public UploadController(IHostingEnvironment hostingEnvironment, NorthwindContext context)
        {
            this.hostingEnvironment = hostingEnvironment;
            this.context = context;
        }

Then you can use this.context inside the UploadFiles method.

I think it's about there. I know it is trying to save to the DB now as I get an error about my foreign key constraint. When I debug in VS Code I can now see that my ordId parameter is not being passed in now and I don't know why. It was working yesterday as I could see the value. I checked the parameter setting for the invoke custom method in Radzen and it is still there and is using the ${parameters.OrderID} that is being used to pull the record on the edit screen.

The Order ID should be 10248 not 0

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting; 
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Data.SqlClient;
using FunTimes.Models.Northwind;
using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication;

namespace UploadFiles.Controllers
{

    [Route("upload")]
    public partial class UploadController : Controller
    {

        private readonly IHostingEnvironment hostingEnvironment;
        private FunTimes.Data.NorthwindContext context;

        public UploadController(IHostingEnvironment hostingEnvironment, FunTimes.Data.NorthwindContext context)
        {
            this.hostingEnvironment = hostingEnvironment;
            this.context = context;
        }


        [HttpPost]
        public IActionResult UploadFiles(IEnumerable<IFormFile> files, int ordId)
        {
            // Combine the orderId with the WebRootPath so files are stored per orderId
            var dir = Path.Combine(hostingEnvironment.WebRootPath, ordId.ToString());
            // Create the directory if it doesn't exist
            Directory.CreateDirectory(dir);

            var result = files.Select(file =>
            {
                // Save the files in the directory
                var path = Path.Combine(dir, file.FileName);

                using (var stream = new FileStream(path, FileMode.Create))
                {
                    // Save the file
                    file.CopyTo(stream);

                    var request = HttpContext.Request;

                    // Create the URL for the uploaded file - not that orderId is part of the URL
                    var url = $"{request.Scheme}://{request.Host.Value}/{ordId}/{file.FileName}";

                    //Save the Record as an Order Attachment.
                    var t = new OrderAttachment
                    {

                        FileName = file.FileName,
                        Url = url,
                        OrderId = ordId
                    };

                    this.context.OrderAttachments.Add(t);
                    this.context.SaveChanges();

                // Return the FileName and Url
                return new
                {
                    fileName = file.FileName,
                    Url = url,
                    OrderId = ordId
                };      

            }
            
        }).ToList();

        // Return the file names and URL of the uploaded files
        return Json(new { value = result }, new JsonSerializerSettings()
        {
            ContractResolver = new DefaultContractResolver()
        });

    }

}

}

Not sure why that parameter isn't set. As a Radzen Professional user you can send us your project to info@radzen.com so we can troubleshoot.

I sent an email.

Thanks,

Josh

Hi Josh,

Since you are executing the upload method as custom server method you should remove the URL setting for the upload:

Best Regards,
Vladimir

That did it. Thanks! :grinning:

1 Like

Hello!
Please help me figure out how to upload files, and by writing file links and id orders to the database
Everything turned out like Josh did, but I can’t insert the record
MySQL database
thank

Can you debug to see if there are any errors when this.context.SaveChanges(); is executed?

Continuing the discussion from Uploading files:

Thank you Vladimir

When debug starts, after a while, the following crashes.

And in the browser, this is what happens.

According to the exception SQL column FileName cannot be null however it is. You need to set this property.

Please tell me how to do this, my level in programming is very low to solve such a difficult task.
thank :relieved:

Here is what @joshwilliam did:

//Save the Record as an Order Attachment.
var t = new OrderAttachment
{

    FileName = file.FileName,
    Url = url,
    OrderId = ordId
};

this.context.OrderAttachments.Add(t);
this.context.SaveChanges();

It is thanks to @joshwilliam that I am now at this stage.
But nothing works, I fight for a very long time, no strength)

Here is the upload controller code:
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Data.SqlClient;
using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication;

namespace UploadFiles.Controllers
{
  using Models;
  using Data;
  using Models.Northwind;
  
    [Route("upload")]
    public partial class UploadController : Controller
    {

        private readonly IHostingEnvironment hostingEnvironment;
        private UploadFiles.Data.NorthwindContext context;

        public UploadController(IHostingEnvironment hostingEnvironment, UploadFiles.Data.NorthwindContext context)
        {
            this.hostingEnvironment = hostingEnvironment;
            this.context = context;
        }


        [HttpPost]
        public IActionResult UploadFiles(IEnumerable<IFormFile> files, int orderId)
        {
            // Combine the orderId with the WebRootPath so files are stored per orderId
            var dir = Path.Combine(hostingEnvironment.WebRootPath, orderId.ToString());
            // Create the directory if it doesn't exist
            Directory.CreateDirectory(dir);

            var result = files.Select(file =>
            {
                // Save the files in the directory
                var path = Path.Combine(dir, file.FileName);

                using (var stream = new FileStream(path, FileMode.Create))
                {
                    // Save the file
                    file.CopyTo(stream);

                    var request = HttpContext.Request;

                    // Create the URL for the uploaded file - not that orderId is part of the URL
                    var url = $"{request.Scheme}://{request.Host.Value}/{orderId}/{file.FileName}";

                    //Save the Record as an Order Attachment.
                      var t = new OrderAttachment
					{

						FileName = file.FileName,
						Url = url,
						OrderId = orderId
					};

					this.context.OrderAttachments.Add(t);
					this.context.SaveChanges();
					  
					

                // Return the FileName and Url
                return new
                {
                    fileName = file.FileName,
                    Url = url,
                    OrderId = orderId
                };      

            }
            
        }).ToList();

        // Return the file names and URL of the uploaded files
        return Json(new { value = result }, new JsonSerializerSettings()
        {
            ContractResolver = new DefaultContractResolver()
        });

    }
}
}