I am trying to upload a file using webapi (.NET6 ). There is no errors in the code . But warnings are there.I have getting below messge in terminal when I run the .csproj file.
warning CS8618: Non-nullable property 'files' must contain a non-null value
when exiting constructor. Consider declaring the property as nullable.
While I runs, Getting this message and running stops. Warning shows in fileModel.cs at files
I have tried putting IFormFile?. still showing warnings and not runs.
I'm Using VS Code. wwwroot folder is created.
My file model:
fileModel.cs
{
public class fileModel
{
public IFormFile files {get; set;}
}
}
Controller file
FilesController.cs
public class FilesController : ControllerBase
{
[HttpPost]
public string UploadFile(fileModel objFile)
{
try
{
if (objFile.files.Length > 0)
{
UploadFile(objFile);
return "Upload" + objFile.files.FileName;
}
else
{
return "Failed";
}
}
catch (System.Exception ex)
{
return ex.Message.ToString();
}
}
}
Interface & Implementation:
IFileUpload.cs:
public interface IFileUpload
{
public void UploadFile(fileModel formFile);
}
FileUpload.cs
public class FileUpload : IFileUpload
{
private IWebHostEnvironment environment;
public FileUpload(IWebHostEnvironment _enviornment)
{
environment = _enviornment;
}
//
public void UploadFile(fileModel formFile){
if (!Directory.Exists(environment.WebRootPath + "\\Uploads"))
{
Directory.CreateDirectory(environment.WebRootPath + "\\Uploads");
}
using(FileStream fileStream = System.IO.File.Create(environment.WebRootPath + "\\Uploads"+formFile.files.FileName)){
formFile.files.CopyTo(fileStream);
fileStream.Flush();
}
}
}
While I runs, Getting this message and running stops. Warning shows in
fileModel.cs at files.
Well, its pretty obvious that it will stop suddenly because you haven't initialize your IFileUpload interface into your controller class therefore, it will certainly break the execution. You ought to write that in following manners:
Controller With Constructor:
public class FilesController : Controller
{
private readonly IFileUpload _fileUplaod;
public FilesController(IFileUpload fileUplaod)
{
_fileUplaod = fileUplaod;
}
[HttpPost]
public IActionResult UploadFile(fileModel objFile)
{
try
{
if (objFile.files.Length > 0)
{
_fileUplaod.UploadFile(objFile);
return Ok("Upload" + objFile.files.FileName);
}
else
{
return Ok("Failed");
}
}
catch (System.Exception ex)
{
return Ok(ex.Message.ToString());
}
}
}
Program.cs
You must register above interface on your program.cs file as following
builder.Services.AddScoped<IFileUpload, FileUpload>();
Output
Execution Debugging Result:
Related
According to Microsoft's recommendation, throwing and catching should not be used for the normal logic of the program.
Minimize exceptions
As part of a ASP.Net core clean architecture project (with 3 Layers Generic Repositories - BL Services - Controllers), how should the error handling and the results be designed and implemented?
Should a struct or a global result class be used for all Api Controllers and BL services?
Is it enough if the errors and the results are encapsulated in a struct?
Example of result class in the WebApi project:
public class ExampleResult<T>
{
public ExampleResult(T value, string message, bool success)
{
(...)
}
}
Controller:
public ActionResult<ExampleResult<NewResourceDto>> Post([FromBody] NewResourceDto myNewResource)
{
try
{
if(!Validate(myNewResource))
return new ExampleResult(null, "some business logic validate failed", true);
ExampleResult result = _service.TrySaveMyNewResource(myNewResource);
return result;
}
catch (Exception ex)
{
// Log the exception here...
return new ExampleResult(null, "some message" + ex, false);
}
}
The Angular Client then validates if the value is null and/or whether the success is true or false.
The message contains the error messages.
The http status will be 200 (no matter if success or not).
How are the exceptions minimized elegantly?
targeting the best practice in .Net Core or any other framework you need to return a common model of all of your apis that holds all the date returned from your api in case if it's a result or an error then in your angular service you should check on your returned object keys which is your base model.
public class ErrorModel
{
public ErrorModel()
{
ErrorMessages = new List<string>();
}
public List<string> ErrorMessages { get; set; }
public Exception Exception { get; set; }
}
public class BaseModel
{
public BaseModel()
{
Error = new ErrorModel();
}
public ErrorModel Error { get; set; }
}
public class BaseModel<T>: BaseModel
{
public BaseModel()
{
Error = new ErrorModel();
}
public bool HasError => Error.ErrorMessages.Count > 0 || Error.Exception != null;
public T Result { get; set; }
}
then your api should look like that
public ActionResult<BaseModel<dynamic>> Post([FromBody] NewResourceDto myNewResource)
{
try
{
ExampleResult result = _service.TrySaveMyNewResource(myNewResource);
return OK( new BaseModel<dynamic>()
{
Result=result
});
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, new BaseModel<dynamic>()
{
Error = new ErrorModel()
{
ErrorMessages = new List<string>()
{
ex.Message,
"your message 2",
"your message 3"
},
Exception = ex
}
});
}
}
then in your angluar service you shold check on your response.hasError and displays your data according to it.
I agree that throwing Exceptions should not be used as signaling in the system. Maybe I don't understand your question about the returning a struct or a global result class. Seems like a bad idea. Especially, don't return HTTP OK 200 if something goes south.
Keep your Web API controllers as thin and dumb as possible
Wrap your Web API controller method methods in a try-catch so you always return HTTP Internal Server Error 500 on an unexpected error
Example of a controller method:
public IActionResult Post([FromBody] NewResourceDto myNewResource)
{
try
{
_service.TrySaveMyNewResource(myNewResource);
return StatusCode(201);
}
catch (Exception ex)
{
// Log the exception here...
return StatusCode(500);
}
}
I currently have the below code which I thought would work however I am receiving a "HttpControllerContext.Configuration must not be null" error when I create the Ok result. The goal is to be able to call any function in a controller in one line to keep my controllers clean. Such as "return ApiUtilities.TryCatch(() => _someService.Get(id));"
I only have access to 'Ok()', "NotFound()" and "InternalServerError()" because the ApiUtilities Class inherits from ApiController
public IHttpActionResult TryCatch<T>(Func<T> operation)
{
try
{
if (ModelState.IsValid)
{
var result = operation();
return Ok(result);
}
}
else
{
return BadRequest();
}
}
catch (Exception error)
{
return InternalServerError();
}
Edit:
My controller looks like this
public class PageController : ApiController
{
private ISomeService _someService;
private ApiUtilities _apiUtilities;
public PageController(ISomeService someService)
{
_someService= someService;
_apiUtilities = new ApiUtilities();
}
[Route("api/page")]
public IHttpActionResult Get([FromBody]string url)
{
return _apiUtilities.TryCatch(() => _someService.Get(url));
}
}
Below is the update I've made based on a Friend's suggestion. I've removed the inheritance on the ApiController. I've also returned the same models the Ok, BadRequest and NotFound functions generate using the context of the current api.
public static class ApiUtilities
{
public static IHttpActionResult TryCatch(Action action, ApiController apiController)
{
try
{
if (apiController.ModelState.IsValid)
{
action();
return new OkResult(apiController);
}
else
{
return new BadRequestResult(apiController);
}
}
catch (Exception error)
{
return new NotFoundResult(apiController);
}
}
public static IHttpActionResult TryCatch<T>(Func<T> operation, ApiController apiController)
{
try
{
if (apiController.ModelState.IsValid)
{
var result = operation();
return new OkNegotiatedContentResult<T>(result, apiController);
}
else
{
return new BadRequestResult(apiController);
}
}
catch (Exception error)
{
return new NotFoundResult(apiController);
}
}
}
Folder not getting created in Local Disk C using Custom Action of a Wix Installer.
namespace MyCustomAction
{
public class CustomActions
{
[CustomAction]
public static ActionResult MySimpleAction(Session session)
{
string country = session["COUNTRIES"];
string root = #"C:\Temp";
try
{
if (!Directory.Exists(root))
{
System.IO.Directory.CreateDirectory(root);
File.AppendAllText(#"C:\Temp\country.txt", country);
}
}
catch (Exception)
{
return ActionResult.Failure;
}
return ActionResult.Success;
}
}
}
I have a customer's DNN site with a custom module that's having issues with module error logging. The site was upgraded to version 7.4 from 6.2 and now to version 9.0. Module exceptions no longer appear in Admin / Host Events since the upgrade to 7.4. It appears module exception logging was changed in DNN 7.4 as explained here. This is the code that worked before but now nothing gets logged;
Test object:
public class foo
{
public int id { get; set; }
public string bar { get; set; }
}
Test webapi Controller:
[DnnAuthorize]
public class MyCustomModuleController : DnnApiController
{
private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(MyCustomModuleController));
[HttpGet]
public HttpResponseMessage GetFoo(int id)
{
try
{
foo test = null;
var bar = test.bar; //will throw null exception
...
}
catch (Exception ex)
{
Logger.Error(ex); //no log entries in db since ver. 7.4
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Server error");
}
}
Is there a setting that I should enable or is there a new way of logging events?
It is my understanding that DotNetNuke.Instrumentation.GetLogger() returns the logging object for doing the Log4Net logging to file appender logs stored in: /Portals/_default/Logs. You can also view them from Host > Host Settings > Logs.
Normally, you would add to your class by setting it up in a constructor and calling the .Error()/.ErrorFormat(), .Warn()/.WarnFormat(), etc functions to append an error or information message to the logging file.
public class MyCustomModuleController : DnnApiController
{
private DotNetNuke.Instrumentation.ILog Logger { get; set; }
public MyCustomModuleController()
{
Logger = DotNetNuke.Instrumentation.LoggerSource.Instance.GetLogger(this.GetType());
}
public HttpResponseMessage GetFoo(int id)
{
try
{
...
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
}
The other logging technique available is using the DotNetNuke.Services.Exceptions to log the exception to the database. These errors get added to the EventLog and Exceptions tables.
public class MyCustomModuleController : DnnApiController
{
public HttpResponseMessage GetFoo(int id)
{
try
{
...
}
catch (Exception ex)
{
DotNetNuke.Services.Exceptions.Exceptions.LogException(ex);
}
}
}
It is possible that DNN disconnected the Log4Net process with the EventLog. I can't remember how it worked back in version 6.
I have two controllers:
public class AController : Controller
{
public ActionResult AControllerAction()
{
if (// BControllerAction reported an error somehow )
{
ModelState.AddModelError("error-key", "error-value");
}
...
}
}
public class BController : Controller
{
public ActionResult BControllerAction()
{
try{Something();}
catch(SomethingExceprion)
{
// here I need to add error info data,
// pass it to AController and redirect to
// AControllerAction where this error will be added
// to model state
}
}
}
I think I can do something like:
public ActionResult BControllerAction()
{
try{Something();}
catch(SomethingException)
{
var controller = new AController();
controller.ModelState.AddModelError("error-key", "error-value");
controller.AControllerAction();
}
}
But I suggest it will be architecture breaking approach, and I don't want to do like that. Is there some simpler and safer way, except passing model object?
Depending on what details of the exception you need to pass back to Controller A, I would do something along the lines of
public ActionResult BControllerAction()
{
try{Something();}
catch(SomethingException ex)
{
return RedirectToAction("AControllerAction", "AController", new { errorMessage = ex.Message() })
}
}
And then change the signature of the called method to
public ActionResult AControllerAction(string errorMessage)
{
if (!String.IsNullOrEmpty(errorMessage))
{
//do something with the message
}
...
}
You can return a redirect to AControllerAction. You can use the TempData dictionary (similar to ViewData) to share data across such a call (data stored this way will persist to the next request in the same session, as explained in this blog post).
Example:
public class AController : Controller
{
public ActionResult AControllerAction()
{
if (TempData["BError"] != null)
{
ModelState.AddModelError("error-key", "error-value");
}
...
}
}
public class BController : Controller
{
public ActionResult BControllerAction()
{
try{Something();}
catch(SomethingExceprion)
{
TempData["BError"] = true;
return RedircetToAction("AControllerAction", "AController");
}
}
}