System.Exception, xUnit calling HttpDelete action on the controller - asp.net-mvc

I'm getting "System.Exception : Exception of type 'System.Exception' was thrown." when I'm calling:
var result = controllerApi.DeleteCliente(2);
the DeleteCliente code (inside the controller):
[Authorize(Roles = "PaginaDeClientes")]
[HttpDelete]
public IActionResult DeleteCliente(int clienteId)
{
var cliente = _context.Clientes.Find(clienteId);
if (cliente == null) { return NotFound(); }
_context.Clientes.Remove(cliente);
var result = _context.SaveChanges();
if (result <= 0)
{
throw new Exception();
}
return Ok();
}
My test DeleteCliente():
[Fact]
public void DeleteCliente()
{
var controllerApi = new PoollGest.Controllers.Api.ClientesController(_context);
_context.Clientes.Add(new Cliente()
{
ClienteId = 2,
Nome = "Jose",
Desconto = 20,
});
var result = controllerApi.DeleteCliente(2);
Assert.IsType<OkResult>(result);
}
This controller currently only has the deleteCliente action, for reference I have run other tests where I create an object in my context and run one of the "crud" action's and I had no problems, not sure what I'm doing wrong here
Error:

I couldn't find the exact cause of the problem when I run the debug with the breakpoints, but it works now.
I Basically rebuild the entire project, deleted the migrations, build the bd again. And it works now, so if you have a similar problem I recommend you to rebuild your project.

Related

Adding child entity works locally but not on live Azure site

I have a web app controller action that is creating a child entity. I have a Location model with a LocationPic collection. I'm trying to add a new LocationPic to an existing Location. Locally this works fine, but when I run it on Azure the LocationPic gets created but doesn't reference the Location. So I end up with an orphaned LocationPic that doesn't know what Location it belongs to.
Also, it works fine locally and on Azure for Locations that ALREADY have pics (I have a separate API controller that seems to work fine). So I can add new pics to Locations that already have some. But I can't add new pics to a new Location that doesn't have any pics.
Here's my controller action:
// POST: Pictures/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("LocationID,Name,Description")] LocationPic locationPic, IFormFile image)
{
var location = await _context.Locations.FindAsync(locationPic.LocationID);
if (location == null)
{
return NotFound();
}
Trace.TraceInformation($"Create Pic for location[{location.LocationID}:{location.LocationName}]");
_userService = new UserService((ClaimsIdentity)User.Identity, _context);
if (!_userService.IsAdmin)
{
return Unauthorized();
}
if (image == null)
{
return BadRequest();
}
if (String.IsNullOrEmpty(locationPic.Name))
{
locationPic.Name = image.FileName;
}
var helper = new AzureTools();
var filename = await helper.GetFileName(image);
locationPic.FileName = filename;
//Added this to try to force LocationPics to be initialized
if (location.LocationPics == null)
{
Trace.TraceInformation("location.LocationPics is null");
location.LocationPics = new List<LocationPic>();
}
else
{
Trace.TraceInformation($"location.LocationPics count == {location.LocationPics.Count}");
}
if (ModelState.IsValid)
{
Trace.TraceInformation($"Location pic valid: [{locationPic.LocationID}] {locationPic.Name}");
//Overly-explicit attempts to get entities linked
locationPic.Location = location;
location.LocationPics.Add(locationPic);
//I've tried _context.LocationPics.Add as well and seemingly no difference
_context.Add(locationPic);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Edit), new { locationID = location.LocationID });
} else
{
Trace.TraceInformation("Invalid model state");
return BadRequest();
}
}
All the right information seems to be coming into my parameters from my form properly, and the LocationPic gets created fine. It just isn't linked to the Location, despite the "LocationID" showing properly before being saved. Plus, I get the proper redirect back to the Edit action, not a BadRequest or anything.
Locally, the only difference I've noticed is that a Location with no pics has a LocationPics that is an empty collection with Count==0. On Azure, a Location with no pics seems to have a LocationPics that is null. So that's why I tried to add the bit that initializes it if it's null, though my API controller that works didn't need to do anything of the sort.
Here's my (working) API Controller action, for reference:
[HttpPost("{id}", Name = "PostPicture")]
public async Task<IActionResult> PostPicture([FromRoute] int id, IFormFile image, string Name, string Description)
{
var location = _context.Locations.Find(id);
if (location == null)
{
return NotFound();
}
_userService = new UserService((ClaimsIdentity)User.Identity, _context);
if (!_userService.IsCustomer(location.CustomerID))
{
return Unauthorized();
}
if (image == null)
{
return BadRequest();
}
if (String.IsNullOrEmpty(Name))
{
Name = image.FileName;
}
var helper = new AzureTools();
var filename = await helper.GetFileName(image);
var locationPic = new LocationPic
{
Name = Name,
FileName = filename,
Description = Description,
Location = location
};
_context.LocationPics.Add(locationPic);
_context.SaveChanges();
return Ok(filename);
}
Turns out the location pics were going in fine, but in my controller actions that I was displaying them I wasn't using .Include() to include the LocationPics collection? Except that it worked for Locations that previously had location pics? And it worked locally totally fine for everything. So I'm not entirely sure.
As soon as I put .Include() to include the LocationPics collection in my "EditByLocation" controller action that grabs a location by ID and sends that to the view that displays the location and pics for that location, all the previous pics I'd added popped into view on the locations that I thought weren't getting them. So for some reason, Location A (with pics) was displaying its pics fine, but Location B (apparently with pics but I couldn't see them until now) wasn't displaying them. I had no reason to believe that the locations weren't displaying correctly because some were displaying fine, and others came over with a null LocationPics collection. So that makes no sense to me. But it seems to be working now.
For completeness, here is my final controller action code, which you may notice looks very similar to the API controller action, which is what it looked like to start with:
// POST: Pictures/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("LocationID,Name,Description")] LocationPic locationPic, IFormFile image)
{
var location = await _context.Locations.FindAsync(locationPic.LocationID);
if (location == null)
{
return NotFound();
}
_userService = new UserService((ClaimsIdentity)User.Identity, _context);
if (!_userService.IsAdmin)
{
return Unauthorized();
}
if (image == null)
{
return BadRequest();
}
if (String.IsNullOrEmpty(locationPic.Name))
{
locationPic.Name = image.FileName;
}
var helper = new AzureTools();
var filename = await helper.GetFileName(image);
locationPic.FileName = filename;
if (ModelState.IsValid)
{
locationPic.Location = location;
_context.LocationPics.Add(locationPic);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(EditByLocation), new { locationID = location.LocationID });
}
return View("EditByLocation", location);
}
And here's my new EditByLocation controller action:
// GET: Pictures/EditByLocation?locationID=5
public async Task<IActionResult> EditByLocation(int locationID)
{
_userService = new UserService((ClaimsIdentity)User.Identity, _context);
if (!_userService.IsAdmin)
{
return Unauthorized();
}
ViewData["ImageBaseUrl"] = _config["AzureStorage:Url"] + "/" + _config["AzureStorage:Folder"];
var location = await _context.Locations.Include(l => l.LocationPics).FirstOrDefaultAsync(l => l.LocationID == locationID);
if (location == null)
{
return NotFound();
}
if (location.LocationPics == null)
{
location.LocationPics = new List<LocationPic>();
}
return View("EditByLocation", location);
}
The only real change above was adding the .Include(l => l.LocationPics). So again, no idea why it worked locally without it, and why SOME locations worked on Azure without it but not others.

Manual Elmah Logging dosnt work properly in MVC

I used ELAMH 1.2 to log errors in MVC 5. It work well for 404 500... HTTP errors and in controller's catch blocks.
public ActionResult Index()
{
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("test"));
try
{
var a = 0;
var b = 1 / a;
}
catch(Exception e)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(e);
}
return View();
}
i get two log for this code.
but it dosent work in a static class like below. i dont get any exception while running ErrorSignal.FromCurrentContext().Raise(e);.
public static class FileUtility
{
public static string SaveSampleFile(HttpPostedFileBase file)
{
try
{
var b = 0;
var a = 1/b;
}
catch (Exception e)
{
ErrorSignal.FromCurrentContext().Raise(e);
return null;
}
}
}
no error log nothing happen!
I have also seen this problem when calling ELMAH logger without any HttpContext in class library projects.
I used the old manual way to get around this:
Elmah.ErrorLog.GetDefault(null).Log(new Error(ex));

'System.Linq.IQueryable<NewsSite.Models.Domain.Tbl_News>' does not contain a definition

I Create A News Site With MVC5 But I Have Problem .
in Model i Create A Repository Folder And in this i Create Rep_Setting for
Connect to Tbl_Setting in DataBase .
public class Rep_Setting
{
DataBase db = new DataBase();
public Tbl_Setting Tools()
{
try
{
var qGetSetting = (from a in db.Tbl_Setting
select a).FirstOrDefault();
return qGetSetting;
}
catch (Exception)
{
return null;
}
}
}
And i Create a Rep_News for Main Page .
DataBase db = new DataBase();
Rep_Setting RSetting = new Rep_Setting();
public List<Tbl_News> GetNews()
{
try
{
List<Tbl_News> qGetNews = (from a in db.Tbl_News
where a.Type.Equals("News")
select a).OrderByDescending(s => s.ID).Skip(0).Take(RSetting.Tools().CountNewsInPage).ToList();
return qGetNews;
}
catch (Exception ex)
{
return null;
}
}
But This Code Have Error to Me
OrderByDescending(s=>s.ID).Skip(0).Take(RSetting.Tools().CountNewsInPage).ToList();
Error :
Error 18 'System.Linq.IQueryable<NewsSite.Models.Domain.Tbl_News>' does
not contain a definition for 'Take' and the best extension method overload
'System.Linq.Queryable.Take<TSource>(System.Linq.IQueryable<TSource>, int)' has
some invalid arguments
E:\MyProject\NewsSite\NewsSite\Models\Repository\Rep_News.cs 50 52 NewsSite
How i Resolve it ?
Try it this way. The plan of debugging is to split your execution, this also makes for a more reusable method in many cases. And a good idea is to avoid using null and nullables if you can, if you use them "on purpose" the you must have a plan for them.
DataBase db = new DataBase();
Rep_Setting RSetting = new Rep_Setting();
public List<Tbl_News> GetNews()
{
int skip = 0;
Tbl_Setting tools = RSetting.Tools();
if(tools == null){ throw new Exception("Found no rows in the database table Tbl_Setting"); }
int? take = tools.CountNewsInPage;//Nullable
if(!take.HasValue)
{
// Do you want to do something if its null maybe set it to 0 and not null
take = 0;
}
string typeStr = "News";
List<Tbl_News> qGetNews = (from a in db.Tbl_News
where a.Type.Equals(typeStr)
select a).OrderByDescending(s => s.ID).Skip(skip).Take(take.Value);
return qGetNews.ToList();
}
if qGetNews is a empty list you now don't break everything after trying to iterate on it, like your return null would. instead if returning null for a lit return a new List<>() instead, gives you a more resilient result.
So I said reusable method, its more like a single action. So you work it around to this. Now you have something really reusable.
public List<Tbl_News> GetNews(string typeStr, int take, int skip = 0)
{
List<Tbl_News> qGetNews = (from a in db.Tbl_News
where a.Type.Equals(typeStr)
select a).OrderByDescending(s => s.ID).Skip(skip).Take(take);
return qGetNews.ToList();
}
Infact you shjould always try to avoid returning null if you can.
public class Rep_Setting
{
DataBase db = new DataBase();
public Tbl_Setting Tools()
{
var qGetSetting = (from a in db.Tbl_Setting
select a).FirstOrDefault();
if(qGetSetting == null){ throw new Exception("Found no rows in the database table Tbl_Setting"); }
return qGetSetting;
}
}

TinyIoC Returning Same instance

I am new to the dependency injection pattern and I am having issues getting a new instance of a class from container.Resolve in tinyioc it just keeps returning the same instance rather than a new instance. Now for the code
public abstract class HObjectBase : Object
{
private string _name = String.Empty;
public string Name
{
get
{
return this._name;
}
set
{
if (this._name == string.Empty && value.Length > 0 && value != String.Empty)
this._name = value;
else if (value.Length < 1 && value == String.Empty)
throw new FieldAccessException("Objects names cannot be blank");
else
throw new FieldAccessException("Once the internal name of an object has been set it cannot be changed");
}
}
private Guid _id = new Guid();
public Guid Id
{
get
{
return this._id;
}
set
{
if (this._id == new Guid())
this._id = value;
else
throw new FieldAccessException("Once the internal id of an object has been set it cannot be changed");
}
}
private HObjectBase _parent = null;
public HObjectBase Parent
{
get
{
return this._parent;
}
set
{
if (this._parent == null)
this._parent = value;
else
throw new FieldAccessException("Once the parent of an object has been set it cannot be changed");
}
}
}
public abstract class HZoneBase : HObjectBase
{
public new HObjectBase Parent
{
get
{
return base.Parent;
}
set
{
if (value == null || value.GetType() == typeof(HZoneBase))
{
base.Parent = value;
}
else
{
throw new FieldAccessException("Zones may only have other zones as parents");
}
}
}
private IHMetaDataStore _store;
public HZoneBase(IHMetaDataStore store)
{
this._store = store;
}
public void Save()
{
this._store.SaveZone(this);
}
}
And the derived class is a dummy at the moment but here it is
public class HZone : HZoneBase
{
public HZone(IHMetaDataStore store)
: base(store)
{
}
}
Now since this is meant to be an external library I have a faced class for accessing
everything
public class Hadrian
{
private TinyIoCContainer _container;
public Hadrian(IHMetaDataStore store)
{
this._container = new TinyIoCContainer();
this._container.Register(store);
this._container.AutoRegister();
}
public HZoneBase NewZone()
{
return _container.Resolve<HZoneBase>();
}
public HZoneBase GetZone(Guid id)
{
var metadataStore = this._container.Resolve<IHMetaDataStore>();
return metadataStore.GetZone(id);
}
public List<HZoneBase> ListRootZones()
{
var metadataStore = this._container.Resolve<IHMetaDataStore>();
return metadataStore.ListRootZones();
}
}
However the test is failing because the GetNewZone() method on the Hadrian class keeps returning the same instance.
Test Code
[Fact]
public void ListZones()
{
Hadrian instance = new Hadrian(new MemoryMetaDataStore());
Guid[] guids = { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
int cnt = 0;
foreach (Guid guid in guids)
{
HZone zone = (HZone)instance.NewZone();
zone.Id = guids[cnt];
zone.Name = "Testing" + cnt.ToString();
zone.Parent = null;
zone.Save();
cnt++;
}
cnt = 0;
foreach (HZone zone in instance.ListRootZones())
{
Assert.Equal(zone.Id, guids[cnt]);
Assert.Equal(zone.Name, "Testing" + cnt.ToString());
Assert.Equal(zone.Parent, null);
}
}
I know its probably something simple I'm missing with the pattern but I'm not sure, any help would be appreciated.
First, please always simplify the code to what is absolutely necessary to demonstrate the problem, but provide enough that it will actually run; I had to guess what MemoryMetaDataStore does and implement it myself to run the code.
Also, please say where and how stuff fails, to point others straight to the issue. I spent a few minues figuring out that the exception I was getting was your problem and you weren't even getting to the assertions.
That said, container.Resolve<HZoneBase>() will always return the same instance because that's how autoregistration in TinyIoC works - once an abstraction has been resolved, the same instance is always returned for subsequent calls.
To change this, add the following line to the Hadrian constructor:
this._container.Register<HZoneBase, HZone>().AsMultiInstance();
This will tell the container to create a new instance for each resolution request for HZoneBase.
Also, Bassetassen's answer about the Assert part is correct.
In general, if you want to learn DI, you should read Mark Seemann's excellent book "Dependency Injection in .NET" - not quite an easy read as the whole topic is inherently complex, but it's more than worth it and will let you get into it a few years faster than by learning it on your own.
In your assert stage you are not incrementing cnt. You are also using the actual value as the expected one in the assert. This will be confusing, becuase it says something is excpected when it actually is the actual value that is returned.
The assert part should be:
cnt = 0;
foreach (HZone zone in instance.ListRootZones())
{
Assert.Equal(guids[cnt], zone.Id);
Assert.Equal("Testing" + cnt.ToString(), zone.Name);
Assert.Equal(null, zone.Parent);
cnt++;
}

Session Variables Lost Between Controllers & Action Methods

I have almost exactly the same scenario described by Nathon Taylor in ASP.NET MVC - Sharing Session State Between Controllers. The problem is that if I save the path to the images inside a Session variable List<string> it is not being defined back in the ItemController so all the paths are being lost... Here's my setup:
Inside ImageController I have the Upload() action method:
public ActionResult Upload()
{
var newFile = System.Web.HttpContext.Current.Request.Files["Filedata"];
string guid = Guid.NewGuid() + newFile.FileName;
string itemImagesFolder = Server.MapPath(Url.Content("~/Content/ItemImages/"));
string fileName = itemImagesFolder + "originals/" + guid;
newFile.SaveAs(fileName);
var resizePath = itemImagesFolder + "temp/";
string finalPath;
foreach (var dim in _dimensions)
{
var resizedPath = _imageService.ResizeImage(fileName, resizePath, dim.Width + (dim.Width * 10/100), guid);
var bytes = _imageService.CropImage(resizedPath, dim.Width, dim.Height, 0, 0);
finalPath = itemImagesFolder + dim.Title + "/" + guid;
_imageService.SaveImage(bytes, finalPath);
}
AddToSession(guid);
var returnPath = Url.Content("~/Content/ItemImages/150x150/" + guid);
return Content(returnPath);
}
private void AddToSession(string fileName)
{
if(Session[SessionKeys.Images] == null)
{
var imageList = new List<string>();
Session[SessionKeys.Images] = imageList;
}
((List<string>)Session[SessionKeys.Images]).Add(fileName);
}
Then inside my ItemController I have the New() action method which has the following code:
List<string> imageNames;
var images = new List<Image>();
if (Session[SessionKeys.Images] != null) //always returns false
{
imageNames = Session[SessionKeys.Images] as List<string>;
int rank = 1;
foreach (var name in imageNames)
{
var img = new Image {Name = name, Rank = rank};
images.Add(img);
rank++;
}
}
Ok so why is this happening and how do I solve it?
Also, I was thinking of whether I could move the ActionMethod that takes care of the upload of the images into the ItemController and store the image paths inside a List property on the ItemController itself, would that actually work? Note though, that images are being uploaded and taken care of via an AJAX request. Then when the user submits the item entry form, all the data about the Item along with the images should be saved to the database...
Update:
I've updated the code. Also I think I should add that I'm using StructureMap as my controller factorory. Could it be a scoping issue? What is the default scope that is usually used by StructureMap?
public class StructureMapDependencyResolver : IDependencyResolver
{
public StructureMapDependencyResolver(IContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
if (serviceType.IsAbstract || serviceType.IsInterface)
{
return _container.TryGetInstance(serviceType);
}
else
{
return _container.GetInstance(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances<object>()
.Where(s => s.GetType() == serviceType);
}
private readonly IContainer _container;
}
And inside my Global.asax file:
private static IContainer ConfigureStructureMap()
{
ObjectFactory.Configure(x =>
{
x.For<IDatabaseFactory>().Use<EfDatabaseFactory>();
x.For<IUnitOfWork>().Use<UnitOfWork>();
x.For<IGenericMethodsRepository>().Use<GenericMethodsRepository>();
x.For<IUserService>().Use<UsersManager>();
x.For<IBiddingService>().Use<BiddingService>();
x.For<ISearchService>().Use<SearchService>();
x.For<IFaqService>().Use<FaqService>();
x.For<IItemsService>().Use<ItemsService>();
x.For<IMessagingService>().Use<MessagingService>();
x.For<IStaticQueriesService>().Use<StaticQueriesService>();
x.For < IImagesService<Image>>().Use<ImagesService>();
x.For<ICommentingService>().Use<CommentingService>();
x.For<ICategoryService>().Use<CategoryService>();
x.For<IHelper>().Use<Helper>();
x.For<HttpContext>().HttpContextScoped().Use(HttpContext.Current);
x.For(typeof(Validator<>)).Use(typeof(NullValidator<>));
x.For<Validator<Rating>>().Use<RatingValidator>();
x.For<Validator<TopLevelCategory>>().Use<TopLevelCategoryValidator>();
});
Func<Type, IValidator> validatorFactory = type =>
{
var valType = typeof(Validator<>).MakeGenericType(type);
return (IValidator)ObjectFactory.GetInstance(valType);
};
ObjectFactory.Configure(x => x.For<IValidationProvider>().Use(() => new ValidationProvider(validatorFactory)));
return ObjectFactory.Container;
}
Any thoughts?
I just added this to Global.asax.cs
protected void Session_Start()
{
}
It seems that this fixed the issue. I set a breakpoint that gets hit only once per session (as expected).
One possible reason for this is that the application domain restarts between the first and the second actions and because session is stored in memory it will be lost. This could happen if you recompile the application between the two. Try putting a breakpoints in the Application_Start and Session_Start callbacks in Global.asax and see if they are called twice.
Are you ever using it other than accessing HttpContext.Current directly in your code? In other words, are there any places where you're injecting the HttpContext for the sake of mocking in unit tests?
If you're only accessing it directly in your methods, then there's no reason to have the entry x.For<HttpContext>().HttpContextScoped().Use(HttpContext.Current); in you application startup. I wonder if it would start working if you removed it.

Resources