Hello everyone I'm a beginner in MVC3. My question is about using class. I'm using web services to get parameter at this point I have no problem but my problem is I'm defining every connection in each controller method again and again so is there any shorcut ?
Here is an example:
public ActionResult BeyanListe()
{
Services_building client = new Services_built();
Services client_service = new Services();
client_service.ClientCredentials.UserName.UserName = "service_test";
client_service.ClientCredentials.UserName.Password = "..";
client_service.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
client.ClientCredentials.UserName.UserName = "service_test";
client.ClientCredentials.UserName.Password = "..";
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
return View()
}
As you can see top I have declared two times for clientcredentials
Make client_service and client protected or private members of the controller.
Move your initialization code to the constructor of the controller.
Use client_service and client in your actions as needed.
If you use this same pattern across multiple controllers you may want to consider creating a controller base class that handles this function.
I assume that both service classes are derived from same interface, eg. IServices, then:
private void AssignCredentials(IServices services)
{
services.ClientCredentials.UserName.UserName = "service_test";
services.ClientCredentials.UserName.Password = "..";
services.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
}
and in your base method call AssignCredentials method.
Related
I am exposing my repository operations through web api. Repository has been implemented with Entity framework and Unit Of Work Pattern. I have many instances of the same database. Each one represent the data of a different Client. Now the issue is how can I set the connection string dynamically through each webapi call? Should I get connection string parameter with each call ? Or I should host web Api per client ?
Based on the information provided, I would use the same controller and look up the connection string rather than rather than hosting separate Web API instances for each client. There would be more complexity in hosting multiple instances and given the only difference indicated is the connection string, I do not think the complexity would be justified.
The first thing we will need to do is determine which client is calling in order to get the appropriate connection string. This could be done with tokens, headers, request data, or routing. Routing is simplest and most generally accessible to clients, so I will demonstrate using it; however, carefully consider your requirements in deciding how you will make the determination.
[Route( "{clientId}" )]
public Foo Get( string clientId ) { /* ... */ }
Next we need to get the right DbContext for the client. We want to keep using DI but that is complicated in that we do not know until after the Controller is created what connection string is needed to construct the object. Therefore, we need to inject some form of factory rather than the object itself. In this case we will represent this as a Func<string, IUnitOfWork> with the understanding it takes the 'clientId' as a string and returns an appropriately instantiated IUnitOfWork. We could alternatively use a named interface for this.
[RoutePrefix("foo")]
public class FooController : ApiController
{
private Func<string, IUnitOfWork> unitOfWorkFactory;
public FooController( Func<string, IUnitOfWork> unitOfWorkFactory )
{
this.unitOfWorkFactory = unitOfWorkFactory;
}
[Route( "{clientId}" )]
public Foo Get( string clientId )
{
var unitOfWork = unitOfWorkFactory(clientId);
// ...
}
}
All that remains is configuring our dependency injection container to provide us that Func<string, IUnitOfWork>. This could vary significantly between implementation. The following is one possible way to do it in Autofac.
protected override void Load( ContainerBuilder builder )
{
// It is expected `MyDbContext` has a constructor that takes the connection string as a parameter
// This registration may need to be tweaked depending on what other constructors you have.
builder.Register<MyDbContext>().ForType<DbContext>().InstancePerRequest();
// It is expected `UnitOfWork`'s constructor takes a `DbContext` as a parameter
builder.RegisterType<UnitOfWork>().ForType<IUnitOfWork>().InstancePerRequest();
builder.Register<Func<string, Bar>>(
c =>
{
var dbContextFactory = c.Resolve<Func<string, DbContext>>();
var unitOfWorkFactory = c.Resolve<Func<DbContext, IUnitOfWork>>();
return clientId =>
{
// You may have injected another type to help with this
var connectionString = GetConnectionStringForClient(clientId);
return unitOfWorkFactory(dbContextFactory(connectionString));
};
});
}
Autofac is used since comments indicates Autofac is currently being used, though similar results would be possible with other containers.
With that the controller should be able to be instantiated and the appropriate connection string will be used for each request.
Example registration based on linked project:
builder.Register<Func<string, IEmployeeService>>(
c =>
{
var dbContextFactory = c.Resolve<Func<string, IMainContext>>();
var unitOfWorkFactory = c.Resolve<Func<IMainContext, IUnitOfWork>>();
var repositoryFactory = c.Resolve<Func<IMainContext, IEmployeeRepository>>();
var serviceFactory = c.Resolve<Func<IUnitOfWork, IEmployeeService>>();
return clientId =>
{
// You may have injected another type to help with this
var connectionString = GetConnectionStringForClient(clientId);
IMainContext dbContext = dbContextFactory(connectionString);
IUnitOfWork unitOfWork = unitOfWorkFactory(dbContext);
IEmployeeRepository employeeRepository = repositoryFactory(dbContext);
unitOfWork.employeeRepositoty = employeeRepository;
return serviceFactory(unitOfWork);
};
});
If you find the registration grows too cumbersome because of needing to do a little wiring manually, you probably need to look at updating (or creating a new) container after you have determined the client so that you can rely more on the container.
You can change the connectionstring per DbContext instance
Example:
public class AwesomeContext : DbContext
{
public AwesomeContext (string connectionString)
: base(connectionString)
{
}
public DbSet<AwesomePeople> AwesomePeoples { get; set; }
}
And then use your DbContext like this:
using(AwesomeContext context = new AwesomeContext("newConnectionString"))
{
return context.AwesomePeoples.ToList();
}
Depending on how many ConnectionStrings there are you can make a DB table for the client / constring mapping or save it in the solution (array for example).
If you can't/don't want to change the constructor you can do it later as well
Add this to your DbContext override:
public void SetConnectionString(string connectionString)
{
this.Database.Connection.ConnectionString = connectionString;
}
And call the method before you do any DB operations:
using(AwesomeContext context = new AwesomeContext())
{
context.SetConnectionString(ConfigurationManager.ConnectionStrings["newConnectionString"].ConnectionString)
return context.AwesomePeoples.ToList();
}
I have an n-tier application, whereas the core web service is built with Web API. many of the web service's methods are set as HTTPGET and accept a DTO object as parameter. my client app, built with MVC 5 is using HttpClient to call this API.
so it seems that by using client.PostAsJsonAsync() I can pass an object, whereas client.GetAsync() doesn't allow me to do that. this forces me to explicitly specify the properties of DTO in the URL, which works, but seem a bit redundant.
Can somebody explain why this is not possible through a GET call and suggest a better practice?
Why does passing data in the URI seem redundant? The HTTP spec says that GET methods are not to use content sent in the body. This is primarily to facilitate caches being able to cache responses based only on the URI, method and headers. Requiring caches to parse the body of a message to identify a resource would be very inefficient.
Here is an basic extension method that will do the grunt work for you,
public static class UriExtensions
{
public static Uri AddToQuery<T>(this Uri requestUri,T dto)
{
Type t = typeof (T);
var properties = t.GetProperties();
var dictionary = properties.ToDictionary(info => info.Name,
info => info.GetValue(dto, null).ToString());
var formContent = new FormUrlEncodedContent(dictionary);
var uriBuilder = new UriBuilder(requestUri) {Query = formContent.ReadAsStringAsync().Result};
return uriBuilder.Uri;
}
}
and assuming you have a DTO like this,
public class Foo
{
public string Bar { get; set; }
public int Baz { get; set; }
}
you can use it like this.
[Fact]
public void Foo()
{
var foo = new Foo()
{
Bar = "hello world",
Baz = 10
};
var uri = new Uri("http://example.org/blah");
var uri2 = uri.AddToQuery(foo);
Assert.Equal("http://example.org/blah?Bar=hello+world&Baz=10", uri2.AbsoluteUri);
}
I have an ASP.NET MVC4 Web API project with an ApiController-inheriting controller that accepts an ODataQueryOptions parameter as one of its inputs.
I am using NUnit and Moq to test the project, which allow me to setup canned responses from the relevant repository methods used by the ApiController. This works, as in:
[TestFixture]
public class ProjectControllerTests
{
[Test]
public async Task GetById()
{
var repo = new Mock<IManagementQuery>();
repo.Setup(a => a.GetProjectById(2)).Returns(Task.FromResult<Project>(new Project()
{
ProjectID = 2, ProjectName = "Test project", ProjectClient = 3
}));
var controller = new ProjectController(repo.Object);
var response = await controller.Get(2);
Assert.AreEqual(response.id, 2);
Assert.AreEqual(response.name, "Test project");
Assert.AreEqual(response.clientId, 3);
}
}
The challenge I have is that, to use this pattern, I need to pass in the relevant querystring parameters to the controller as well as the repository (this was actually my intent). However, in the case of ODataQueryOptions-accepting ApiController methods, even in the cases where I would like to use just the default parameters for ODataQueryOptions, I need to know how to instantiate one. This gets tricky:
ODataQueryOptions does not implement an interface, so I can't mock it directly.
The constructor requires an implementation of System.Web.Http.OData.ODataQueryContext, which requires an implementation of something implementing Microsoft.Data.Edm.IEdmModel, for which the documentation is scarce and Visual Studio 2012 Find References and View Call Hierarchy do not provide insight (what implements that interface?).
What do I need to do/Is there a better way of doing this?
Thanks.
Looks like someone else already answered this in the comments here, but it's not a complete solution for my use-case (see comment below):
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Customer>("Customers");
var opts = new ODataQueryOptions<Customer>(new ODataQueryContext(modelBuilder.GetEdmModel(),typeof(Customer)), request);
This is the solution I have been using in my NUnit tests to inject ODataQueryOptions
private static IEdmModel _model;
private static IEdmModel Model
{
get
{
if (_model == null)
{
var builder = new ODataConventionModelBuilder();
var baseType = typeof(MyDbContext);
var sets = baseType.GetProperties().Where(c => c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>));
var entitySetMethod = builder.GetType().GetMethod("EntitySet");
foreach (var set in sets)
{
var genericMethod = entitySetMethod.MakeGenericMethod(set.PropertyType.GetGenericArguments());
genericMethod.Invoke(builder, new object[] { set.Name });
}
_model = builder.GetEdmModel();
}
return _model;
}
}
public static ODataQueryOptions<T> QueryOptions<T>(string query = null)
{
query = query ?? "";
var url = "http://localhost/Test?" + query;
var request = new HttpRequestMessage(HttpMethod.Get, url);
return new ODataQueryOptions<T>(new ODataQueryContext(Model, typeof(T)), request);
}
I've followed this Prevent Forms authentication in order to try and handle redirecting from ajax gracefully. However I need to be able to determine if certain attributes are decorating the action that this call was made for as I only want to do this for some occasions. Can I get this information from the HttpRequest object that is accessible within this method?.
Essentially taking the part from the code above that I would like to manipulate:
public class SuppressFormsAuthenticationRedirectModule : IHttpModule {
private void OnPostReleaseRequestState(object source, EventArgs args) {
var context = (HttpApplication)source;
var response = context.Response;
var request = context.Request; // request is HttpRequest
if (response.StatusCode == 401 && request.Headers["X-Requested-With"] ==
"XMLHttpRequest") {
// TODO HERE: Check that the controller action contains a particular attribute
// and if so do not suppress redirect
SuppressAuthenticationRedirect(context.Context);
}
}
}
UPDATE:
It's probably worth noting that this code is held within a compiled DLL project that is then encorporated into a host MVC application (which we don't have access to). In that case I don't really have access to changing default implementations unless I can ensure it doesn't effect the rest of the controllers in the application.
I tried to use as much of the framework as possible, which is why I chose to expose the GetControllerType method from the DefaultControllerFactory. You'll notice that routeData contains the area, controller and action, so with a bit of reflection, you can bypass having to create a derived controller factory.
This is definitely not production ready. It is just a way to get the custom attributes from the requested action.
Edit: instead of setting the current controller factory, create a new DerivedControllerFactory
var httpApplication = (HttpApplication)sender;
var httpContext = new HttpContext(httpApplication.Request, new HttpResponse(new StringWriter()));
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
//var factory = ControllerBuilder.Current.GetControllerFactory() as DerivedControllerFactory;
var factory = new DerivedControllerFactory();
var controllerType = factory.GetControllerType(new RequestContext(new HttpContextWrapper(httpContext), routeData), routeData.Values["controller"].ToString());
var methodInfo = controllerType.GetMethod(routeData.Values["action"].ToString());
var attributes = methodInfo.GetCustomAttributes(true);
public class DerivedControllerFactory : DefaultControllerFactory
{
public new Type GetControllerType(RequestContext requestContext, string controllerName)
{
return base.GetControllerType(requestContext, controllerName);
}
}
We use MVC3, for our unit tests we use RhinoMocks in our unit tests.
When the a request starts we check the domain from which it came and match that to a customer.
This customer is stored in the HttpContext.Items.
Most controllers need this info to do their thing.
var mocks = new MockRepository();
using (var controller = new TestController())
{
HttpContext context =
MockRepository.GenerateStub<HttpContext>();
Customer customer = new Customer { Key = "testKey" };
context.Items["Customer"] = customer;
controller.ControllerContext =
new ControllerContext {
Controller = controller,
RequestContext =
new RequestContext(
new HttpContextWrapper(context),
new RouteData()
)
};
...
This code sample shows basically what is needed, however the stub is not allowed as HttpContext is a "sealed" class.
The controller accepts a HttpContextBase (there is lot about mocking this one), but it does not expose the Items property.
Thoughts anyone? Or even better a solution ;-)
Creating a HttpContextBase stub and stubbing its Items property will allow you to use the Items dictionary:
HttpContextBase context =
MockRepository.GenerateStub<HttpContextBase>();
Customer customer = new Customer { Key = "testKey" };
context.Stub(c => c.Items).Return(new Dictionary<string, object>());
context.Items["Customer"] = customer;