Can someone help please?
I have in my controller the create action:
public class MovieController : Controller
{
Connect connection = new Connect();
Movie movie = new Movie();
[HttpPost]
public ActionResult Create(Movie moviecreated)
{
try
{
// TODO: Add insert logic here
connection.Connection().AddObject(moviecreated);
connection.Connection().Context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View(movie);
}
}
}
my connection class
public class Connect
{
public ObjectSet<Movie> Connection()
{
var connStr = ConfigurationManager.ConnectionStrings["Entities"];
ObjectContext context = new ObjectContext(connStr.ConnectionString);
var movieContext = context.CreateObjectSet<Movie>();
return movieContext;
}
}
It is not saving the new addition, what have I got wrong?
Thanks much.
try this:
public class MovieController : Controller
{
private Connect connection;
private Movie movie;
public MovieController()
{
this.connection = new Connect();
this.movie = new Movie();
}
[HttpPost]
public ActionResult Create(Movie moviecreated)
{
try
{
// TODO: Add insert logic here
this.connection.MovieContext.AddObject(moviecreated);
this.connection.MovieContext.Context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View(movie);
}
}
}
public class Connect
{
private ObjectSet<Movie> movieContext;
public ObjectSet<Movie> MovieContext
{
get
{
if (this.movieContext == null)
{
this.SetMovieContext();
}
return this.movieContext;
}
}
public void SetMovieContext()
{
var connStr = ConfigurationManager.ConnectionStrings["Entities"];
var context = new ObjectContext(connStr.ConnectionString);
this.movieContext = context.CreateObjectSet<Movie>();
}
}
Each time you call connection() it creates another instance.Once you add the new record another , you try to save but different context.
Change it to a property and so save your context.
Related
I want to call a method of controller A from controller B and get its return value.
How can I do that?
ControllerA:
[HttpGet]
public async Task<ParentModel> GetParentModel(string contractNumberPar)
{
try
{
// (...) - some code
var viewModel = new ParentModel
{
// (...) - some code
};
return viewModel;
}
catch (Exception ex)
{
throw;
}
}
ControllerB:
ParentModel viewModel = RedirectToAction(
"ControllerA",
"GetParentModel",
new
{
contractNumberPar = contractNumber
});
Error message:
Cannot implicitly convert type microsoft.aspnetcore.mvc.redirecttoaction to (....).ParentModel
You'd better create a common service,so that you can reuse it in both A and B controllers,here is a demo:
service:
public class MyService
{
public async Task<ParentModel> GetParentModel(string contractNumberPar)
{
try
{
// (...) - some code
var viewModel = new ParentModel
{
// (...) - some code
};
return viewModel;
}
catch (Exception ex)
{
throw;
}
}
}
register the service(before .net6 in Startup.cs):
services.AddScoped<MyAccountService>();
register the service(.net6,.net7 in Program.cs):
builder.Services.AddScoped<MyService>();
BController:
public class BController : Controller
{
private readonly MyService MyService;
public BController(MyService myService)
{
MyService = myService;
}
public async Task<IActionResult> IndexAsync()
{
string contractNumber="1";
ParentModel viewModel = await MyService.GetParentModel(contractNumber);
return Ok(viewModel);
}
}
I am having a simple controller which needs to be unit tested not integration tested. I just need a way to mock so that I can verify if receive method is called. We already have test against Receive(), so no need to verify what is going inside that method.
My code looks like
public class MessageController : Controller
{
private readonly ConnectionDetail connectionDetail;
private readonly QueueDetail queueDetail;
public MessageController(IOptions<ConnectionDetail> connectionDetail, IOptions<QueueDetail> queueDetail)
{
this.connectionDetail = connectionDetail.Value;
this.queueDetail = queueDetail.Value;
}
[HttpGet()]
public IActionResult Get()
{
try
{
var channel = CreateConnectionAndChannel(queueDetail);
var message = channel.Receive();
var hbaseKey = new HbaseKey { Key = new Guid(message) };
return Ok(hbaseKey);
}
catch
{
return StatusCode(500, "Exception occured while processing. Try again.");
}
}
private IChannel CreateConnectionAndChannel(QueueDetail queueDetail)
{
var factory = new Factory();
var adapter = factory.Connect(MessagingType.MQ, connectionDetail);
return adapter.BindQueue(queueDetail);
}
}
Refactor the CreateConnectionAndChannel function out into its own service
public interface IChannelProvider {
IChannel CreateConnectionAndChannel();
}
and have controller explicitly depend on that service
public class MessageController : Controller {
private readonly IChannelProvider channelProvider;
public MessageController(IChannelProvider channelProvider) {
this.channelProvider = channelProvider;
}
[HttpGet()]
public IActionResult Get() {
try {
var channel = channelProvider.CreateConnectionAndChannel();
var message = channel.Receive();
var hbaseKey = new HbaseKey { Key = new Guid(message) };
return Ok(hbaseKey);
} catch {
return StatusCode(500, "Exception occured while processing. Try again.");
}
}
}
So now only the IChannelProvider needs to be mocked to test the controller in isolation.
I just need a way to mock so that I can verify if receive method is called.
public void Verify_Received_Called() {
//Arrange
var channel = new Mock<IChannel>();
channel
.Setup(_ => _.Receive())
.Returns("My mock value here");
var mockProvider = new Mock<IChannelProvider>();
mockProvider.Setup(_ => _.CreateConnectionAndChannel())
.Returns(channel.Object);
var controller = new MessageController(mockProvider.Object);
//Act
var result = controller.Get();
//Assert
channel.Verify(_ => _.Receive(), Times.AtLeastOnce);
}
The provider implementation could look like...
public class ChannelProvider : IChannelProvider {
private readonly ConnectionDetail connectionDetail;
private readonly QueueDetail queueDetail;
public ChannelProvider(IOptions<ConnectionDetail> connectionDetail, IOptions<QueueDetail> queueDetail) {
this.connectionDetail = connectionDetail.Value;
this.queueDetail = queueDetail.Value;
}
public IChannel CreateConnectionAndChannel() {
var factory = new Factory();
var adapter = factory.Connect(MessagingType.MQ, connectionDetail);
return adapter.BindQueue(queueDetail);
}
}
In order to do this, you need to move your CreateConnectionAndChannel method to a separate dependency, for instance, ChannelFactory which implements IChannelFactory interface.
public interface IChannelFactory {
IChannel CreateConnectionAndChannel(QueueDetail queueDetail);
}
public class ChannelFactory : IChannelFactory {
public IChannel CreateConnectionAndChannel(QueueDetail queueDetail)
{
var factory = new Factory();
var adapter = factory.Connect(MessagingType.MQ, connectionDetail);
return adapter.BindQueue(queueDetail);
}
}
public class MessageController : Controller
{
private readonly ConnectionDetail connectionDetail;
private readonly QueueDetail queueDetail;
private readonly IChannelFactory channelFactory;
public MessageController(IOptions<ConnectionDetail> connectionDetail, IOptions<QueueDetail> queueDetail, IChannelFactory channelFactory)
{
this.connectionDetail = connectionDetail.Value;
this.queueDetail = queueDetail.Value;
this.channelFactory = channelFactory;
}
[HttpGet()]
public IActionResult Get()
{
try
{
var channel = channelFactory.CreateConnectionAndChannel(queueDetail);
var message = channel.Receive();
var hbaseKey = new HbaseKey { Key = new Guid(message) };
return Ok(hbaseKey);
}
catch
{
return StatusCode(500, "Exception occured while processing. Try again.");
}
}
}
After that you can mock your controller in test (using Moq for example):
[TestFixture]
public class TestMessageController
{
[Test]
public void TestGet()
{
var channelMock = new Mock<IChannel>(MockBehavior.Strict);
channelMock
.Setup(c => c.Receive())
.Returns(null);
var channelFactoryMock = new Mock<IChannelFactory>(MockBehavior.Strict);
channelFactory
.Setup(cf => cf.CreateConnectionAndChannel(It.IsAny<IOptions<QueueDetail>>()))
.Returns();
var controller = new MessageController(null, null, channelFactoryMock.Object);
controller.Get();
}
}
I have created a database in mongodb using asp.net mvc but when i look to my database the insertion is failed .I have tested before in a console application and it works correctly but now I don't find the problem when i use mvc!can you help me please
this is my code
//IDeviseRepository
namespace WebApplication6
{
public interface IDeviseRepository
{
Devise Add(Devise devise);
void MongoGoNow();
}
}
//DeviseRepository
namespace WebApplication6
{
public class DeviseRepository : IDeviseRepository
{
public IMongoDatabase db;
public DeviseRepository()
{
MongoClientSettings settings = new MongoClientSettings();
settings.Server = new MongoServerAddress("localhost", 27017);
MongoClient client = new MongoClient(settings);
this.db = client.GetDatabase("bigdata");
var collection = db.GetCollection<Devise>("Devise");
}
public IMongoCollection<Devise> Devise
{
get
{ return db.GetCollection<Devise>("Devise"); }
}
public Devise Add(Devise devise)
{
var collection = db.GetCollection<Devise>("Devise");
collection.InsertOne(devise);
return devise;
}
public void MongoGoNow()
{
var collection = db.GetCollection<Devise>("devise");
var result = TestFind(collection);
result.GetAwaiter().GetResult();
}
static async Task TestFind(IMongoCollection<Devise> MyCollection)
{
var filter = new BsonDocument();
var count = 0;
using (var cursor = await MyCollection.FindAsync(filter))
{
while (await cursor.MoveNextAsync())
{
var batch = cursor.Current;
foreach (var document in batch)
{
count++;
}
}
}
}
public void insertdata()
{
var devise = new Devise();
devise.parité = "euro/dollar";
Devise.InsertOne(devise);
}
}
}
Try updating your insert to:
public void insertdata()
{
try
{
var devise = new Devise();
devise.parité = "euro/dollar";
Devise.InsertOne(devise);
}
catch (Exception ex)
{
//put a breakpoint here
}
}
I have lots of controllers methods in WebAPI similar to the following:
public IHttpActionResult Delete(int id)
{
var command = new DeleteItemCommand() { Id = id };
try
{
_deleteCommandHandler.Handle(command);
}
catch (CommandHandlerResourceNotFoundException)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
catch(CommandHandlerException)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
// More catches etc...
return Ok();
}
The command handlers (in this instance _deleteCommandHandler) is injected earlier in the execution and the commands may be built in the method or using WebApi's automatic method.
What I would like to do is to encapsulate the try/catch error handling in a private method and end up with a controller similar to:
public IHttpActionResult Delete(int id)
{
var command = new DeleteItemCommand() { Id = id };
return ExecuteCommand(x => _deleteCommandHandler.Handle(command));
}
I'm not sure what the signature of the private ExecuteCommand method should be though.
I think you can Invoke your action in a method like this:
public IHttpActionResult Delete(int id)
{
return ExecuteCommand(() => {
var command = new DeleteItemCommand() { Id = id };
_deleteCommandHandler.Handle(command);
});
}
private IHttpActionResult ExecuteCommand(Action action)
{
try
{
action.Invoke();
//or: action();
}
catch (CommandHandlerResourceNotFoundException)
{
return HttpResponseException(HttpStatusCode.NotFound);
}
catch (CommandHandlerException)
{
return HttpResponseException(HttpStatusCode.InternalServerError);
}
return Ok();
}
A good reference for HttpResponseException.
I would create a custom error handler filter, and handle all possible errors there in a centralized form. That way you can just throw whatever exception from the action methods, and then they will be caught at the filter where you can handle them and change the response accordingly.
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
}
}
The example is taken from this article where you can find the concept in more detail.
Here's a solution similar to shA.t's answer, but the exceptions are mapped in a dictionary and the try/catch logic is in an extension method:
public class TestController:ApiController
{
public IHttpActionResult Delete(int id)
{
return ExecuteCommand(() => {
var command = new DeleteItemCommand() { Id = id };
_deleteCommandHandler.Handle(command);
});
}
private IHttpActionResult ExecuteCommand(Action action)
{
return action.SafeInvoke();
}
}
public static class ActionExtensions
{
private static readonly Dictionary<Type, HttpStatusCode> _exceptionToStatusCodeLookup = new Dictionary<Type, HttpStatusCode>
{
{typeof(CommandHandlerResourceNotFoundException), HttpStatusCode.NotFound },
{typeof(CommandHandlerException), HttpStatusCode.InternalServerError },
};
public static IHttpActionResult SafeInvoke(this Action action)
{
try
{
action();
}
catch (Exception ex)
{
var statusCode = _exceptionToStatusCodeLookup.ContainsKey(ex.GetType()) ? _exceptionToStatusCodeLookup[ex.GetType()] : HttpStatusCode.InternalServerError;
return new HttpResponseException(statusCode);
}
return new OkResult();
}
}
I have a UsersContext : DbContext with a DbSet Users { get; set; }
UsersController.cs
public class UsersController : Controller
{
private UsersContext db = new UsersContext("dbA");
public ViewResult Index()
{
if (...)
db = new UsersContext("dbA");
else
db = new UsersContext("dbB");
return View(db.Users.ToList());
}
}
This returns the good associated list.
If I choose dbB I have the good list but when I go on detail on one of the results in :
public ViewResult Details(int id)
{
User user = db.Users.Find(id);
return View(user);
}
The db's connectionString is associated to the dbA not the dbB.
Why the new db is not well initilized and saved ?
That is because your Index action and Details action do not execute on the same controller instance. You can keep the database name in a session variable and use that to create the DbContext instance.
public class UsersController : Controller
{
private UsersContext db;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
if (Session["Database"] == null)
db = new UsersContext("dbA");
else
db = new UsersContext((string)Session["Database"]);
}
public ViewResult Index()
{
if (...) {
db = new UsersContext("dbA");
Session
else
{
db = new UsersContext("dbB");
Session["Database"] = "dbB";
}
return View(db.Users.ToList());
}
}