I have two methods with ActionResult return types yet one of them is giving back a single Employee object and still works. Why is that? - asp.net-core

I've just wrote a controller class in a Blazor application and I don't undersand something.
I have a method GetEmployee:
[HttpGet("{employeeId:int}")]
public async Task<ActionResult<Employee>> GetEmployee(int employeeId)
{
try
{
var result = await employeeRepsitory.GetEmployee(employeeId);
if (result == null)
{
NotFound();
}
return result;
}
catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError,
"Error retrieving data from the database");
}
}
The return type is an ActionResult<Employee> but clearly in my method I'm returning an Employee. Because the employeeRepsitory.GetEmployee(employeeId) method gives back a single Employee which is stored in a variable "result".
I have an other method GetEmployees :
[HttpGet]
public async Task<ActionResult<IEnumerable<Employee>>> GetEmployees()
{
try
{
return Ok(await employeeRepsitory.GetEmployees());
}
catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError,
"Error retrieving data from the database");
}
}
Where I put my object in an Ok() ActionResult. If I didn't wrap await employeeRepsitory.GetEmployees() in an Ok() then I have compillation error because I'm not giving back ActionResult. But how does that GetEmployee(int employeeId) method is not giving me compilation error yet I'm clearly giving back an Employee object and not an ActionResult. Thank you for your answers.

Related

PUT request to API is setting values to NULL

I have this .Net Core API controller below that does a PUT request.
The table affected in Sql Server, looks like this:
carID (varchar(15), NULL)
optionID (varchar(15), NOT NULL)
optionDescription (varchar(255), NULL)
optionType (varchar(50), NULL)
factoryID (varchar(15), NULL)
In testing, I am sending along the properties I want changed like this in my PUT API call:
{
" optionID": "633fr",
"optionDescription": "Full Tech Package A"
}
It does update the entry in the database, but it's also setting all the values not sent in the PUT call to NULL. So while it does update optionDescription, it is setting all the other values to NULL except optionID.
How do I stop it from setting the other values?
thanks!
Here is the controller:
// PUT: api/CarOptions/5
[HttpPut("{id}")]
public async Task<IActionResult> PutCarOptions(Guid id, CarOptions carOptions)
{
if (id != carOptions.OptionId)
{
return BadRequest();
}
_context.Entry(carOptions).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CarOptionsExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
According to your description, I suggest you could try to attach the model firstly and then set the specific property IsModified to true.
This will only update specific fields instead of updating whole model.
More details, you could refer to below example:
// PUT: api/CarOptions/5
[HttpPut("{id}")]
public async Task<IActionResult> PutCarOptions(Guid id, CarOptions carOptions)
{
_context.Documents.Attach(carOptions);
_context.Entry(carOptions).Property(x => x.optionDescription).IsModified = true;
_context.SaveChanges();
return NoContent();
}

If criteria not met redirect to different Razor Page from public async Task OnGetAsync()

I am new to the "async" and "task" stuff.
I can't seem to get working a simple if{} else{} inside the OnGetAsync().
public async Task OnGetAsync()
{
if (HttpContext.Session.GetString("LoggedStatus") != null)
{
//KEEP GOING
Accounts = await _context.Accounts.ToListAsync();
}
else
{
RedirectToPage("./Index");
}
}
The error I get is from the Accounts page, which I am trying to avoid even going near by using the "RedirectToPage("./Index")" which is my Home page.
I tried putting "return" word in front of RedirectToPage but it turns red when I do that. Also, if first condition is met (there is a value in the Session object) the Accounts pages shows up with no errors. So, I'm pretty sure the problem is in my attempt to redirect in the "else" statment.
NullReferenceException: Object reference not set to an instance of an object.
OESAC.Pages.Accounts.Pages_Accounts_Index.ExecuteAsync() in Index.cshtml
+
#foreach (var item in Model.Accounts)
The error above is in Accounts right where it loops thru and displays rows.
I'm not sure why it even gets to the Accounts.chstml.
You need to use Task<IActionResult> in public async Task<IActionResult> OnGetAsync(), combined with a return statement.
public async Task<IActionResult> OnGetAsync()
{
if (HttpContext.Session.GetString("LoggedStatus") != null)
{
//KEEP GOING
Accounts = await _context.Accounts.ToListAsync();
return Page();
}
else
{
return RedirectToPage("./Index");
}
}
Microsoft's docs has some good read on this here:
https://learn.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-2.2&tabs=visual-studio
Based on a comment, you can run this w/o async.
public IActionResult OnGet()
{
if (HttpContext.Session.GetString("LoggedStatus") != null)
{
//KEEP GOING
Accounts = _context.Accounts.ToList();
return Page();
}
else
{
return RedirectToPage("./Index");
}
}

Do an action when an error occurs RxJava

I need to create a folder when it doesn't exist. In my case, the only way to do so is to capture the error and handle it to create the folder wanted.
But all i can find is
public static Observable<Boolean> folderExists(final Context context, final String targetPath, final String currentpath) {
Application application = Application.get(context);
//i browse the folder to get all the items
return browseFolderObservable(context,currentpath)
.subscribeOn(application.defaultSubscribeScheduler())
.doOnError(new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
BsSdkLog.d("Error no file found");
}
})
.map(new Func1<ArrayList<Item>, Boolean>() {
#Override
public Boolean call(ArrayList<Item> items) {
if(items.isEmpty()) {
BsSdkLog.d(" No items");
return false;
}else {
for(int i=0;i<items.size();i++)
{
Item item=items.get(i);
BsSdkLog.d(item.toString());
}
BsSdkLog.d("Right-here");
return true;
}
}
});
}
I want to call the method that i have that creates the folder when the error occurs but i don't know how to do that.
I'm new to this so i'd really appreciate the help
Thanks
The basic principe looks like this. I used the Java NIO library for testing.
The method 'createFolder' just wraps creating a folder. The test 'name' invokes the Single and checks for an Exception. If it is an IOException it will return a fallback value. You may do something different in there. You just provide a fallback single. If it is an error different from IOException, it will return the error.
#Test
void name() throws Exception {
final String TO_CREATE = "/home/sergej/Downloads/Wurstbrot";
this.createFolder(TO_CREATE)
.onErrorResumeNext(throwable -> { // handle Exception:
// Validate Exception
if (throwable instanceof IOException) {
// Return fallback
return Single.just(Paths.get("/home/sergej/Downloads/"));
}
return Single.error(throwable);
})
.test()
.await()
.assertValueCount(1)
.assertValue(path -> path.endsWith(TO_CREATE))
.assertNoErrors();
}
private Single<Path> createFolder(String p) {
return Single.defer(() -> { // may throw some IOException
Path path = Paths.get(p);
if (!Files.exists(path)) {
Path createdDirectory = Files.createDirectory(path); // will throw if already exists
return Single.just(createdDirectory);
}
// Or just return Path, because it already exists???
return Single.error(new IOException("Already exists"));
});
}

how to return something from a Ninject Interceptor

I have written a common validator as part of Ninject interceptor. My requirement is that I have to return a response object, just like how any service method in my project returns, for consistency sake. By returning a response object also helps me to send back an appropriate validation message when the validator fails. How do I do that in the interceptor? I understood that the Intercept() returns nothing. I tried throwing an exception but I don't know where to catch it. Can someone help me?
public void Intercept(IInvocation invocation)
{
var validationFails = false;
if (validationFails)
{
// return an object
// response.ErrorMessage = "Validation Error"
// Or throw exception, but where should I catch it
throw new Exception(statusMessage);
}
else
{
invocation.Proceed();
}
}
Assign the ReturnValue and don't call Proceed when validation fails.
public class MyRequestHandler
{
Response ProcessRequest(string input) { return new Response(); }
}
public MyValidationInterceptor : IInterceptor
{
public void Intercept( IInvocation invocation )
{
if (NeedsValidation(invocation.Method) &&
!IsValidRequest((string)invocation.Arguments[0]))
{
invocation.ReturnValue =
new Response { ErrorMessage = "Validation Error" };
return;
}
invocation.Proceed();
}
}
I had to hook up my interceptor to business layer methods, instead of service methods, and am able to return proper return value as part of my response.

Struts2 more than one action in one class

I'm using Struts2. I have two web forms that have the same code. I would like to eliminate one form. Here is the structure of my Struts project.
\Web Pages
form.jsp
\WEB-INF
\Content
error.jsp
form.jsp
success.jsp
\Source Packages
\action
MyAction.java
MyAction.java
package action;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.*;
public class MyAction extends ActionSupport {
#Action(value = "foo", results = {
#Result(name = "input", location = "form.jsp"),
#Result(name = "success", location = "success.jsp"),
#Result(name = "error", location = "error.jsp")
})
public String execute() throws Exception {
if (user.length() == 1) {
return "success";
} else {
return "error";
}
}
private String user = "";
public void validate() {
if (user.length() == 0) {
addFieldError("user", getText("user required"));
}
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
I tried to eliminate form.jsp under \Web Pages by adding a new action method to MyAction.java.
#Action(value="bar", results = {
#Result(name = "success", location = "form.jsp"),
})
public String another() {
return "success";
}
But I got the following error when I go to http : //localhost .../bar.action
HTTP Status 404 - No result defined for action action.MyAction and result input
Your MyAction has an implementation of validate(), which means it is validation aware.
What's happening is that you're calling another, but validate() is kicking in (as it's in the interceptor stack). Validation is failing, and therefore sending to INPUT result, which is not defined in another.
You should
Add #SkipValidation to the another method if you don't want validation there
Add the INPUT result to another() if you want a default input result
On a more general note, when you get that kind of error (No result defined for action X and result input) it usually means you're either having validation errors, parameter population errors (eg: an exception in preparable).