【问题标题】:Error uploading a document to SQL Server in .Net Core 3.1 Web API在 .Net Core 3.1 Web API 中将文档上传到 SQL Server 时出错
【发布时间】:2021-07-21 22:00:17
【问题描述】:

我有一个 SQL Server 存储过程,用于上传文档并在成功时返回 ID。

我将参数 file_data 存储到 Customer_Document_ADD 类中的 byte[] 类型中。

public byte[] file_data { get; set; }

以下是我的仓库代码。

public async Task<int> InsertCustomer_Document_ADDResult(Customer_Document_ADD customer_Document_ADDED)
        {
            await using(SqlConnection connection = new SqlConnection(_connectionString))
            {
                connection.Open();

                // define SqlParameters for the other two params to be passed
                var company_idParam = new SqlParameter("@company_id", customer_Document_ADDED.company_id);
                var customer_idParam = new SqlParameter("@customer_id", customer_Document_ADDED.customer_id);
                var customer_site_idParam = new SqlParameter("@customer_site_id", customer_Document_ADDED.customer_site_id);
                var customer_system_idParam = new SqlParameter("@customer_system_id", customer_Document_ADDED.customer_system_id);
                var job_idParam = new SqlParameter("@job_id", customer_Document_ADDED.job_id);
                var security_levelParam = new SqlParameter("@security_level", customer_Document_ADDED.security_level);
                var file_nameParam = new SqlParameter("@file_name", customer_Document_ADDED.file_name);
                var file_sizeParam = new SqlParameter("@file_size", customer_Document_ADDED.file_size);
                var upload_dateParam = new SqlParameter("@upload_date", customer_Document_ADDED.upload_date);
                var document_extParam = new SqlParameter("@document_ext", customer_Document_ADDED.document_ext);
                var user_codeParam = new SqlParameter("@user_code", customer_Document_ADDED.user_code);
                var user_descriptionParam = new SqlParameter("@user_description", customer_Document_ADDED.user_description);
                var reference1Param = new SqlParameter("@reference1", customer_Document_ADDED.reference1);
                var reference2Param = new SqlParameter("@reference2", customer_Document_ADDED.reference2);
                var reference3Param = new SqlParameter("@reference3", customer_Document_ADDED.reference3);
                var reference4Param = new SqlParameter("@reference4", customer_Document_ADDED.reference4);
                var file_dataParam = new SqlParameter("@file_data", customer_Document_ADDED.file_data);
                //if (file_dataParam.Value == null)
                //{
                //    file_dataParam.Value = "";
                //}
                file_dataParam.SqlDbType = SqlDbType.Image;

                // define the output parameter that needs to be retained
                // for the Id created when the Stored Procedure executes 
                // the INSERT command
                var document_idParam = new SqlParameter("@document_id", SqlDbType.Int);

                // the direction defines what kind of parameter we're passing
                // it can be one of:
                // Input
                // Output
                // InputOutput -- which does pass a value to Stored Procedure and retains a new state
                document_idParam.Direction = ParameterDirection.Output;

                // we can also use context.Database.ExecuteSqlCommand() or awaitable ExecuteSqlCommandAsync()
                // which also produces the same result - but the method is now marked obselete
                // so we use ExecuteSqlRawAsync() instead

                // we're using the awaitable version since GetOrCreateUserAsync() method is marked async
                await context.Database.ExecuteSqlRawAsync(
                    "EXECUTE [dbo].[Customer_Document_ADD_incentive] @company_id, @customer_id, @customer_site_id, @customer_system_id, @job_id, @security_level, @file_name, @file_size, @upload_date, @document_ext, @user_code, @user_description, @reference1, @reference2, @reference3, @reference4, @file_data, @document_id out",
                    company_idParam,
                    customer_idParam,
                    customer_site_idParam,
                    customer_system_idParam,
                    job_idParam,
                    security_levelParam,
                    file_nameParam,
                    file_sizeParam,
                    upload_dateParam,
                    document_extParam,
                    user_codeParam,
                    user_descriptionParam,
                    reference1Param,
                    reference2Param,
                    reference3Param,
                    reference4Param,
                    file_dataParam,
                    document_idParam);

                // the userIdParam which represents the Output param
                // now holds the Id of the new user and is an Object type
                // so we convert it to an Integer and send
                return Convert.ToInt32(document_idParam.Value);
            }
        }

我在 Postman 中收到以下错误。

Microsoft.Data.SqlClient.SqlException (0x80131904): The parameterized query '(@company_id int,@customer_id int,@customer_site_id int,@custome' expects the parameter '@file_data', which was not supplied.
   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   at Microsoft.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader(Boolean isInternal, Boolean forDescribeParameterEncryption)
   at Microsoft.Data.SqlClient.SqlCommand.InternalEndExecuteNonQuery(IAsyncResult asyncResult, Boolean isInternal, String endMethod)
   at Microsoft.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult)
   at Microsoft.Data.SqlClient.SqlCommand.EndExecuteNonQueryAsync(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRawAsync(DatabaseFacade databaseFacade, String sql, IEnumerable`1 parameters, CancellationToken cancellationToken)
   at WebAPI.Repository.Customer_Document_ADDRepository.InsertCustomer_Document_ADDResult(Customer_Document_ADD customer_Document_ADDED) in C:\Users\CStith\source\code\project\WebAPI\WebAPI\Repository\Customer_Document_ADDRepository.cs:line 73
   at WebAPI.Repository.Customer_Document_ADDRepository.InsertCustomer_Document_ADDResult(Customer_Document_ADD customer_Document_ADDED) in C:\Users\CStith\source\code\project\WebAPI\WebAPI\Repository\Customer_Document_ADDRepository.cs:line 97
   at WebAPI.Controllers.Customer_Document_ADDController.InsertCustomer_Document_ADDResult(Customer_Document_ADD customer_Document_ADDED) in C:\Users\CStith\source\code\project\WebAPI\WebAPI\Controllers\Customer_Document_ADDController.cs:line 38
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
ClientConnectionId:e8f735f0-1ab5-4d53-9ead-01df3ee63c2e
Error Number:8178,State:1,Class:16

除了文件之外的所有其他值都被捕获。我在调试器中得到一个空值。为什么我无法将文件上传到数据库?提前致谢。

【问题讨论】:

    标签: sql .net-core entity-framework-core asp.net-core-webapi asp.net-core-3.1


    【解决方案1】:

    首先,默认模型绑定系统无法将文件绑定到byte[]属性。如果你想将文件绑定到btye[],可以使用ByteArrayModelBinder,这里是official link

    另外,如果你不介意改变file_data的类型,你可以使用

    public IFormFile file_data { get; set; }
    

    然后你可以使用MemoryStream将其转换为byte[]类型。这是official link关于在.net core中上传文件的内容。

    【讨论】:

    • 感谢@YiyiYou 的回答。我不是很了解。我在模型类中将类型从 byte 更改为 IFormFile 但现在我在 Postman 中收到以下错误。 System.InvalidOperationException: The property 'Customer_Document_ADD.file_data' is of an interface type ('IFormFile'). If it is a navigation property manually configure the relationship for this property by casting it to a mapped entity type, otherwise ignore the property using the NotMappedAttribute or 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
    • 如果你使用ByteArrayModelBinderpublic byte[] file_data { get; set; },可以吗?
    猜你喜欢
    • 1970-01-01
    • 2020-05-23
    • 2020-08-27
    • 1970-01-01
    • 2020-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多