Reputation: 21
I have an API which is for a CMS that can change my entire 'AboutUs' web page. The following was the Data Model that holds all the contents of that 'About Us' webpage.
I have a Future method that goes this way to update the 'About Us' webpage contents within database only. (via ASP.Net Core web API)
Future updateAboutUsContent() async
Future<AboutUsContextModel> updateAboutUsContent(
String title,
String context,
String subcontext,
PlatformFile imageId,
) async {
final abUC =
await http.put(Uri.parse(urlAddress + "/api/AboutUsContextModels/2"),
headers: <String, String>{
"Content-Type": "multipart/form-data;charset=UTF-8",
},
body: jsonEncode(<String, dynamic>{
"title": title,
"context": context,
"subContext": subcontext
}));
final request = http.MultipartRequest(
"POST", Uri.parse(urlAddress + "/api/AboutUsContextModels/2"));
request.files.add(http.MultipartFile(
"imageFile",
imageId.readStream,
imageId.size,
filename: imageId.name.split("/").last);
var resp = await request.send();
String response = await resp.stream.bytesToString();
print("==================\nThis is the response:\n=================" +
response);
}
if (abUC.statusCode == 200) {
//If the server did return a 200 Created All green post
//then parse the JSON
return AboutUsContextModel.fromJson(jsonDecode(abUC.body));
} else if (abUC.statusCode == 400) {
throw Exception('Error code was 400. About Us Content Not Foun');
} else {
throw Exception('Nothing About Us Content created in Flutter');
}
}
And This Future will call the ASP web API which is as below:
[HttpPut("{id}")]
public async Task<ActionResult<AboutUsContextModel>> PutAboutUsContent(int id, string title, string context, string subcontext, IFormFile imageFile)
{
AboutUsContextModel abUC = await _context.AboutUsContextModel.Include(lim => lim.Image).FirstOrDefaultAsync(limy => limy.AboutUs_Context_Id == id);
if(abUC == null)
{
return BadRequest("No such About Us Content!");
}
if(imageFile != null)
{
ImageModel imgfrmDB = abUC.Image;
if(imgfrmDB != null)
{
string cloudDomaim = "https://privacy-web.conveyor.cloud";
string uploadDrcty = _webEnvr.WebRootPath + "\\Images\\";
if (!Directory.Exists(uploadDrcty))
{
Directory.CreateDirectory(uploadDrcty);
}
string filePath = uploadDrcty + imageFile.FileName;
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await imageFile.CopyToAsync(fileStream);
await fileStream.FlushAsync();
}
using (var memoryStream = new MemoryStream())
{
await imageFile.CopyToAsync(memoryStream);
imgfrmDB.Image_Byte = memoryStream.ToArray();
}
imgfrmDB.ImagePath = cloudDomaim + "/Images/" + imageFile.FileName;
imgfrmDB.Modify_By = "CMS Admin";
imgfrmDB.Modity_dt = DateTime.Now;
}
}
abUC.Title = title;
abUC.Context = context;
abUC.SubContext = subcontext;
abUC.Modify_By = "CMS Admin";
abUC.Modity_dt = DateTime.Now;
_context.Entry(abUC).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!AboutUsContextModelExists(abUC.AboutUs_Context_Id))
{
return NotFound();
}
else
{
throw;
}
}
return Ok("About Us Content Delivered, Edit Successful");
}
Unfortunately when I run the code, the following errors only shows:
TypeError: Cannot read properties of null (reading 'listen')
at byte_stream.ByteStream.new.listen (http://localhost:60452/dart_sdk.js:36349:31)
at _StreamControllerAddStreamState.new._AddStreamState.new (http://localhost:60452/dart_sdk.js:37160:37)
at new _StreamControllerAddStreamState.new (http://localhost:60452/dart_sdk.js:37191:53)
at _AsyncStreamController.new.addStream (http://localhost:60452/dart_sdk.js:36687:24)
at _AsyncStarImpl.new.addStream (http://localhost:60452/dart_sdk.js:33462:46)
at multipart_request.MultipartRequest.new._finalize (http://localhost:60452/packages/http/src/multipart_request.dart.lib.js:352:22)
at _finalize.next (<anonymous>)
at _AsyncStarImpl.new.runBody (http://localhost:60452/dart_sdk.js:33416:40)
at Object._microtaskLoop (http://localhost:60452/dart_sdk.js:40808:13)
at _startMicrotaskLoop (http://localhost:60452/dart_sdk.js:40814:13)
at http://localhost:60452/dart_sdk.js:36279:9
I used breakpoints to examine each of the lines to track where is the null (in the Flutter's updateAboutUsContent() Future), which this line
final abUC =
await http.put(Uri.parse(urlAddress + "/api/AboutUsContextModels/2"),
headers: <String, String>{
"Content-Type": "multipart/form-data;charset=UTF-8",
},
body: jsonEncode(<String, dynamic>{
"title": title,
"context": context,
"subContext": subcontext,
// 'imageFile': imageId
}));
and this line,
final request = http.MultipartRequest(
"POST", Uri.parse(urlAddress + "/api/AboutUsContextModels/2"));
The 'PlatformFile imageFile' receives the imageFile. It shows the filename, bytes,... all those in the VS Code 'Run and Debug'.
The 'PlatformFile imageFile' still gets the image file, but until this line
request.files.add(http.MultipartFile(
"imageFile",
imageId.readStream,
imageId.size,
filename: imageId.name.split("/").last);
it still execute this line but after that the aforementioned TypeError shows. It seems that, MAYBE
http.MultipartFile(
"imageFile",
imageId.readStream,
imageId.size,
filename: imageId.name.split("/").last)
↑↑something here was wrong.↑↑
Referring to the first two codes I pasted at first, i.e. updateAboutUsContent(), and PutAboutUsContent() located in the Web API, Can I know
I'm very new to Flutter web, ASP.NET Core 5.0 web API, and really don't have any idea/concepts about how to upload images to the ASP.NET from flutter web, so something in my updateAboutUsContent() in the Flutter may wrote wrong. I have tested the PutAboutUsContent() situated in the Web API using Swagger UI, nothing there was wrong, and I was prohibited to change the codes there, I just can use it.
So, I plead. Is there someone could lend a hand, please?
UPDATE
Now the Future updateAboutUsContent() async is changed to this:
Future<AboutUsContextModel> putAboutUsContent(
String title,
String context,
String subcontext,
PlatformFile imageId,
) async {
final abUC =
await http.put(Uri.parse(urlAddress + "/api/AboutUsContextModels/2"),
headers: <String, String>{
"Content-Type": "multipart/form-data;charset=UTF-8",
},
body: jsonEncode(<String, dynamic>{
"title": title,
"context": context,
"subContext": subcontext,
// 'imageFile': imageId
}));
final request = http.MultipartRequest(
"PUT", Uri.parse(urlAddress + "/api/AboutUsContextModels/2"));
var fileadded =
new http.MultipartFile("imageFile",
imageId.readStream,
imageId.size,
filename: imageId.name);
if (fileadded != null) {
request.headers
.addAll(<String, String>{"Content-Type": "multipart/form-data"});
request.files.add(fileadded);
var resp = await request.send();
String response = await resp.stream.bytesToString();
print("==================\nThis is the response:\n=================" +
response);
}
if (abUC.statusCode == 200) {
//If the server did return a 200 Created All green post
//then parse the JSON
return AboutUsContextModel.fromJson(jsonDecode(abUC.body));
} else if (abUC.statusCode == 400) {
throw Exception('Error code was 400. About Us Content Not Foun');
} else {
throw Exception('Nothing About Us Content created in Flutter');
}
}
And the Future method can properly go until to the if(statusCode ==??) there, however, it still returns 400. Now, the console appears:
==================
This is the response:
=================Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> Npgsql.PostgresException (0x80004005): 23502: null value in column "Title" of relation "AboutUs_Context" violates not-null constraint
at Npgsql.NpgsqlConnector.<ReadMessage>g__ReadMessageLong|194_0(NpgsqlConnector connector, Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
Exception data:
Severity: ERROR
SqlState: 23502
MessageText: null value in column "Title" of relation "AboutUs_Context" violates not-null constraint
Detail: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
SchemaName: WebContext
TableName: AboutUs_Context
ColumnName: Title
File: d:\pginstaller_13.auto\postgres.windows-x64\src\backend\executor\execmain.c
Line: 1953
Routine: ExecConstraints
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Privacy_Web.Controllers.AboutUsContextModelsController.PutAboutUsContent(Int32 id, String title, String context, String subcontext, IFormFile imageFile) in D:\distributor_dashboard_v2\Privacy_Web\privacy_web_backend\Privacy_Web\Controllers\AboutUsContextModelsController.cs:line 224
at lambda_method299(Closure , Object )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.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.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(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 Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: close
Content-Length: 263429
Content-Type: multipart/form-data; boundary=dart-http-boundary-zMVNRV2ehRqP4TYkdPpFn.dOrsckK2tfoxBV_s6z5coua9ye0+m
Host: localhost:44395
Referer: http://localhost:63925/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
origin: http://localhost:63925
sec-fetch-site: cross-site
sec-fetch-mode: cors
sec-fetch-dest: empty
x-server-sni: haproxy.privacy-web-kb5.conveyor.cloud
x-forwarded-for: (***IP address here, censored to be seen***)
When the first two lines of the updateAboutUsContent() method was executed, ie.
final abUC =
await http.put(Uri.parse(urlAddress + "/api/AboutUsContextModels/2"),
headers: <String, String>{
"Content-Type": "multipart/form-data;charset=UTF-8",
},
body: jsonEncode(<String, dynamic>{
"title": title,
"context": context,
"subContext": subcontext,
// 'imageFile': imageId
}));
final request = http.MultipartRequest(
"PUT", Uri.parse(urlAddress + "/api/AboutUsContextModels/2"));
The following shows:
where the readStream returns: Instance of '_ControllerStream<List>'.
So I think this was the reason statusCode 400 was returned.
So, how should I solve it? Or if I wrongly identified the issue causing the error, then where can I improved?
Upvotes: 1
Views: 1672
Reputation: 1507
You have to send one request with all data.
Something like this:
Future<AboutUsContextModel> putAboutUsContent(
String title,
String context,
String subcontext,
PlatformFile imageId,
) async {
var request = http.MultipartRequest("PUT", Uri.parse(urlAddress + "/api/AboutUsContextModels/2"));
request.fields['title'] = title;
request.fields['context'] = context;
request.fields['subContext'] = subContext;
request.files.add(http.MultipartFile(
'imageFile',
imageId.readStream,
imageId.size,
filename: imageId.name,
));
final resp = await request.send();
if (resp.statusCode == 200) {
//If the server did return a 200 Created All green post
//then parse the JSON
return AboutUsContextModel.fromJson(jsonDecode(resp.body));
} else if (resp.statusCode == 400) {
throw Exception('Error code was 400. About Us Content Not Foun');
} else {
throw Exception('Nothing About Us Content created in Flutter');
}
}
Also, check this answer .
Upvotes: 1