return object after null checking through if in blazor - return

public async Task<ServiceResponse<Product>> GetProductAsync(int productId)
{
var response = new ServiceResponse<Product>()
{
Data = await _context.Products.AsNoTracking().FirstOrDefaultAsync(p => p.Id == productId)
} ;
if ( response.Data == null )
{
response.Success = false ;
response.Message = "Sorry, but this product does not exist." ;
}
else
return response ;
return response ;
}
I am a newbie c# and blazor.
I made productservice.cs file. The above code is the part of it which will return one product class in Gerelic T.
First, I find matched productid in db.
Then, null check. if it is not null it will return response, ok.
I thought at first I will return response as one product to Task T, all code might be good.
But I faced an error in the last line. So I put again 'return response'. Then the error sign was disappeared.
But I think this might be wrong and weird, even though there is no error anymore.
I want to improve this code correctly or efficiently.
May I get your opinion?

The error you faced probably was something like not all code paths return a value. Since your method returns a typed value, and you are using if-else statement -- you have to provide returning value both in if and else clauses.
Extend your ServiceResponse<T> with a constructor that receives some arguments.
Refactor your method in order to stress your product variable for better readability.
Return ServiceResponse using newly-created constructor.
Unfortunately, I can't test it right now to be sure 100%, but you can give it a try.
class ServiceResponse<T>
{
public T Data { get; set; }
public bool IsSuccess { get; set; }
public string Message { get; set; }
public ServiceResponse( T data, string message = "success" )
{
Data = data;
IsSuccess = data != null;
Message = data == null ? "Sorry, but this product does not exist." : message;
}
}
public async Task<ServiceResponse<Product>> GetProductAsync( int productId )
{
var product = await _context.Products.Where( p => p.Id == productId).AsNoTracking().FirstOrDefault();
return new ServiceResponse<Product>( product );
}
Remarks
We don’t have to provide 2nd argument into the constructor while returning the response since it already has the default value defined for the message in the constructor. But you still can do that!
I also set default value for the message there if data == null. Actually, it can be removed if you wish!
IsSuccess is also being regulated by data in the constructor of ServiceResponse<T>
UPD: Tested
if ProductId == 1
{
"data": {
"id": 1,
"name": "Test1"
},
"isSuccess": true,
"message": "success"
}
if ProductId == 2 (which is out of list)
{
"data": null,
"isSuccess": false,
"message": "Sorry, but this product does not exist."
}

Related

Getting deserialized body without binding

I'm starting with Nancy, and I've run into a frustrating issue.
I have a model that has an ID (amongst other properties).
public class MyModel
{
public string Id { get; set; }
// other properties
}
In my module, I defined a PUT method
Put["/{id}", true] = async (parameters, token) =>
{
var model = this.Bind<MyModel>();
string id = parameters["id"];
if (model.Id != id)
return new Response
{
ReasonPhrase = $"[error message about IDs not matching]",
StatusCode = HttpStatusCode.BadRequest
};
await _myModelService.Update(model);
return Nancy.Response.NoBody;
};
The issue I'm experiencing is that at the this.Bind<MyModel>() call, Nancy overwrites the ID in the body with the ID in the route, meaning I can't test my "unmatched" scenario. For example:
PUT /orders/someObjectId
{
"Id" : "aDifferentObjectId"
}
binds to a MyModel with Id as "someObjectId".
I've also tried blacklisting the property:
this.Bind<MyModel>(m => m.Id)
this.Bind<MyModel>("id")
this.Bind<MyModel>("Id")
this.Bind<MyModel>("id", "Id")
However, this results in the bind operation clearing the ID property in the model.
How can I get exactly what's in the body?
Nevermind. I was doing something wrong, and now it's working without the blacklist. I have no explanation.

Error based on Remote Validation in mvc

This is my controller code:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult CheckBuildingName()
{
var isUnique = true;
string _buildingName = Request.Form["buildingName"]; // put your control name here
var connectionstring = ConnectionProvider();
AddBuildingModel model = new AddBuildingModel();
using (var context = new Notifier.AccountDatabase(connectionstring))
{
var objBuilding = (from building in context.Buildings
where building.buildingName == model.buildingName && building.buildingActive == true
select building).FirstOrDefault();
if (objBuilding == null)
{
isUnique = true;
}
else
{
isUnique = false;
}
}
if (isUnique == false)
{
return Json("Building already taken, Pleaes try with different name.", JsonRequestBehavior.AllowGet);
}
else
{
return Json(true, JsonRequestBehavior.AllowGet);
}
}
}
and my model is like below:
[System.ComponentModel.DisplayName("buildingName")]
[Remote("CheckBuildingName", "ConfigLocationController",ErrorMessage = "Building already exists!")]
public string buildingName { get; set; }
I am getting errors on this. The controller path cannot be found out or does not implement IController. What does that mean. Am I missing something ? Or is my code completely wrong. ? Please help
The reason for the error is that your RemoteAttribute is calling the CheckBuildingName method of ConfigLocationControllerController. Assuming that you controller is actually named ConfigLocationController, then you attributes need to be
[Display(Name = "Building Name")] // use this attribute, not DisplayName
[Remote("CheckBuildingName", "ConfigLocation",ErrorMessage = "Building already exists!")]
public string buildingName { get; set; }
However your method also contains errors. You initialize a new instance of a model and then use the value of its buildingName property (which will be null) in your query so it will always return null. In additional, you should add a parameter for the value your ajax call is submitting rather than using Request.Form. You method can be simply
[HttpPost]
public JsonResult CheckBuildingName(string buildingName)
{
bool exists = context.Buildings.Any(x => x.buildingName == buildingName && x.buildingActive);
return Json(!exists, JsonRequestBehavior.AllowGet);
}
which will return true if there is no match, or false if there is, in which case the message you have defined in the attribute will be displayed in the view assuming you have included #Html.ValidationMessageFor(m => m.buildingName)

Returning HttpStatusCodeResult in method that returns PartialViewResult

I have an MVC5 application that has a method populates and returns a partial view. Since the method accepts an ID as a parameter, Id like to return an error if it is not supplied.
[HttpGet] public PartialViewResult GetMyData(int? id)
{
if (id == null || id == 0)
{
// I'd like to return an invalid code here, but this must be of type "PartialViewResult"
return new HttpStatusCodeResult(HttpStatusCode.BadRequest); // Does not compile
}
var response = MyService.GetMyData(id.Value);
var viewModel = Mapper.Map<MyData, MyDataViewModel>(response.Value);
return PartialView("~/Views/Data/_MyData.cshtml", viewModel);
}
What is the proper way to report an error for a method that returns a PartialViewResult as its output?
You could create a friendly error partial and do the following:
[HttpGet]
public PartialViewResult GetMyData(int? id)
{
if (id == null || id == 0)
{
// I'd like to return an invalid code here, but this must be of type "PartialViewResult"
return PartialView("_FriendlyError");
}
var response = MyService.GetMyData(id.Value);
var viewModel = Mapper.Map<MyData, MyDataViewModel>(response.Value);
return PartialView("~/Views/Data/_MyData.cshtml", viewModel);
}
This way there is a better user experience rather than just throwing them anything. You can customise that error partial to include some details that they did wrong etc.
You can use manual Exception
if (id == null || id == 0)
{
throw new Exception("id must have value");
}
if you work with ajax, you can handle error by error callback function
$.ajax({
type: 'POST',
url: '/yourUrl',
success: function (response) {
// call here when successfully // 200
},
error: function (e) {
// handle error in here
}
})
While you cannot return HttpStatusCodeResult as a PartialViewResult to set the response status code for you, you can certainly still do the manual labour yourself to achieve the same result.
Using the OP's example:
[HttpGet]
public PartialViewResult GetMyData(int? id)
{
if (id == null || id == 0)
{
// Return an invalid code here
HttpContext.Response.StatusCode = HttpStatusCode.BadRequest;
// Optionally set the description as well
HttpContext.Response.StatusDescription = "Bad Request";
// Return null as it doesn't matter anymore
return null;
}
var response = MyService.GetMyData(id.Value);
var viewModel = Mapper.Map<MyData, MyDataViewModel>(response.Value);
return PartialView("~/Views/Data/_MyData.cshtml", viewModel);
}
Success, by setting the status code directly on HttpContext.Response which is accessible from the base class Controller, and what HttpStatusCodeResult would've done anyway.
nJoy!

Mvc.net Unit test with a nullable parameter

I am new for unit test with Moq and Nunit. I have a simple unit test for getting a product list. But the test result didn't turn out as expected.
ProductManagementController action is:
public ViewResult Index(int? id)
{
return View(_ProductRepo.GetProductList(id));
}
ProductRepository is:
public IList<Product> GetProductList(int? id)
{
if (id == null)
{
return (db.Products).ToList();
}
else
{
return db.Products.Where(i => i.CategoryId == id).ToList();
}
}
I have two tests setup, but only the first test(get all products list) is fine.
[TestFixture]
public class Test_ProductManagement
{
private List<Product> products;
private List<Category> categories;
private Mock<IProductRepository> mockProducts;
private ProductManagementController target;
[TestFixtureSetUp]
public void Initialize()
{
images = new List<Product> {
new Product{Id = 1, Name = "Boat", CategoryId = 1 },
new Product{Id = 2, Name = "Picture Frame",CategoryId = 2 }
};
categories = new List<Category> {
new Category { Id = 1, Name = "Outdoors" },
new Category { Id = 2, Name = "Housewares" }
};
mockProducts = new Mock<IProductRepository>();
mockProducts.Setup(m => m.GetProductList(It.IsAny<int>())).Returns(products);
target = new ProductManagementController(mockProducts.Object);
}
[Test]
public void Index_Contains_All_Products()
{
//Action
List<Product> result = ((IEnumerable<Product>)target.Index(It.IsAny<int>()).ViewData.Model).ToList();
//Assert
Assert.AreEqual(2, result.Length);
Assert.AreEqual("Boat", result[0].Name);
Assert.AreEqual("Picture Frame", result[1].Name);
}
[Test]
public void Index_Get_ImageList_By_CategoryId()
{ //Arrange
int id = 2;
//Action
List<Product> result = ((IEnumerable<Product>)target.Index(id).ViewData.Model).ToList();
//Assert
Assert.AreEqual(1, result.Count());
Assert.AreEqual("Picture Frame", result[0].Name);
}
The 2nd test always return a full product list which include 2 products while I only expect 1 returned from Assert.AreEqual(1,result.Count());
I can't figure out why test code always take the id as a null parameter in the above index call: target.Index(id) . However all my project codes run correctly in the browsers.
Does anyone has a clue? Thanks.
I can't figure out why test code always take the id as a null parameter in the above index call: target.Index(id)
It doesn't. You don't show all code (specifically how your controller handles the repository injection) and you seem to have renamed at least the products / images field, but the code works just fine.
You call target.Index(id), which in turn calls _ProductRepo.GetProductList(id). I assume this is your mock being called, which is Setup() by you to always return the entire product list.
The mock does exactly what you ask it to, no ProductRepository is used in this code, so your if (id == null) is never executed.
In order to fix this, you must Setup() your mock differently in each test method, or setup both cases in advance:
mockProducts.Setup(m => m.GetProductList(null)).Returns(products);
mockProducts.Setup(m => m.GetProductList(2)).Returns(new List<Product>{products[1]});
Of course you want to setup the latter call somewhat less specific, but I hope you see where you can fix this.

Displaying Data from the database taking Order Id as input in mvc4

I am new to asp and I would like to ask you for some help. I built store with MvcMusicStore tutorial help.Now I want to search in the database by using OrderId.As soon as the orderid is and if we click on the submit button it should display the corresponding rows from the database. My method is as follows
public ActionResult SearchOrder(int? myid)
{
var s = from sp in db.Railways
select sp;
string oid = myid.ToString();
if (!string.IsNullOrEmpty(oid))
{
s = s.Where(st => st.OrderID == (Convert.ToInt16(oid)));
}
return View(s.ToList());
}
Also i tired with the code as
public ActionResult SearchOrder(int? myid)
{
if (id != null)
{
if (ViewBag.OrderID == id.Value)
{
s = s.Where(st => st.OrderID == id);
}
}
return View(s);
}
In the second method when i tried it is neither displaying the contents nor showing the error.
Pls do help me.
Try this:
public ActionResult SearchOrder(int? myid)
{
var s = from sp in db.Railways
select sp;
if (myid.HasValue)
{
s = s.Where(st => st.OrderID == myid.Value);
}
return View(s.ToArray());
}
First your example will not work because string oid = myid.ToString(); will not be null or empty string if myid is null; Second example will fail (ViewBag.OrderID == id.Value) condition and moreover will not compile.

Resources