I am working with a web api where it should have a request key and depending upon it, the api controller will do
specific task. I am using rest client program in vs code and did the following for testing:
GET http://localhost:PortNo/WeatherForecast/GetAllTeams
test: "12345678910" //Key
So in the controller, I did this to get the key value:
[HttpGet]
public async Task<ActionResult<IEnumerable<TeamDetails>>> GetAllTeams()
{
string Token = Request.Headers["test"]; //Getting the key value here
var teams = _service.GetAllTeams();
return Ok(teams)
}
But I've few things in mind and doing R & D like how can I make the above with an attribute. Say each controller
will have an attribute as follows and make the request invalid if no proper key found:
[InvalidToken] //This is the attribute
[HttpGet]
public async Task<ActionResult<IEnumerable<TeamDetails>>> GetAllTeams()
{
var teams = _service.GetAllTeams();
return Ok(teams)
}
I am not sure if this is going to make the api secure and my plan is to valid every http request (In my case, a simple form submission at the moment), so it should say the request is generated from the web api app.
N.B: I worked with web api earlier in small sections but now a broader thing to implement, so expecting few suggestions that can help me to guide for better design.
try it:
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
..
public class InvalidToken : Attribute, IActionFilter
{
public InvalidToken( )
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
var Authorization = context.HttpContext.Request.Headers["test"];
if ( Authorization != "12345678910")
{
context.ModelState.AddModelError("Authorization", "Authorization failed!");
return;
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// "OnActionExecuted"
}
}
Startup.cs
services.AddScoped<InvalidToken>();
// add filter to whole api
services.AddControllers(options =>
{
options.Filters.Add<InvalidToken>();
});
I am new to asp.net and azure mobile services.
Have some questions:
1)I have used the TodoItemController to query data from azure table storage
(just used their sample class as given below)
How do i modify it so that it acts as Generic Class for all Tables and not just for one table.for eg:if i had another Table called person apart from Todo
i want it to use the same class for both tables
2)Is the method Im suggesting a bad design pattern and if so why?
3)I also dint understand how this class gets called.
Saw somewhere that ../tables/Todo
is mapped to this class.if thats the case.Where is the mapping done.?
4)Will ApiController achieve my purpose 1?if So an example please
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.OData;
using Microsoft.WindowsAzure.Mobile.Service;
using TempService.DataObjects;
using TempService.Models;
using System.Web.Http.OData.Query;
using System.Collections.Generic;
namespace TempService.Controllers
{
public class TodoItemController : TableController<TodoItem>
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
// Create a new Azure Storage domain manager using the stored
// connection string and the name of the table exposed by the controller.
string connectionStringName = "StorageConnectionString";
var tableName = controllerContext.ControllerDescriptor.ControllerName.ToLowerInvariant();
DomainManager = new StorageDomainManager<TodoItem>(connectionStringName,
tableName, Request, Services);
}
public Task<IEnumerable<TodoItem>> GetAllTodoItems(ODataQueryOptions options)
{
// Call QueryAsync, passing the supplied query options.
return DomainManager.QueryAsync(options);
}
// GET tables/TodoItem/1777
public SingleResult<TodoItem> GetTodoItem(string id)
{
return Lookup(id);
}
// PATCH tables/TodoItem/1456
public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch)
{
return UpdateAsync(id, patch);
}
// POST tables/TodoItem
public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
// DELETE tables/TodoItem/1234
public Task DeleteTodoItem(string id)
{
return DeleteAsync(id);
}
}
}
So I will try to address your questions by point:
Yes and no. What you are trying to do is follow the Repository Pattern. So yes, you can make a BaseRepository that will do the bulk of the work with a generic data type. No, you will still have classes that inherit the base but specify the generic data type.
No this is not a bad design pattern.
So the TableController is a specialized ApiController for the data table. It is called via the route configuration that translates the URL "/tables/TodoItem/Id"
Again, the TableController is an ApiController. Not sure it will help, but there are a number of examples of the "Repository Pattern" for Azure Mobile Services. You can look here to get an idea:
http://www.codeproject.com/Articles/574357/Repository-Pattern-with-Windows-Azure-Mobile-Servi
I want to implement my custom message handler that will check for a custom header that must be present in every request.
If my custom header is present the request passes through and will hit the controller if the header is not there the request is rejected with custom error message.
No my question is: if I implement my handler that way that means all requests MUST have the header however I need to have a gate where I can call without that header and the request must be ignored by message handler and hit the controller even without the custom header.
Is it possible to achieve this? Or how can I implement my message handler that will ignore certain calls to specific controller or something like this ...?
You can try this.. (untested)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
public abstract class EnforceMyBusinessRulesController : ApiController
{
protected override void Initialize(System.Web.Http.Controllers.HttpControllerContext controllerContext)
{
/*
Use any of these to enforce your rules;
http://msdn.microsoft.com/en-us/library/system.web.http.apicontroller%28v=vs.108%29.aspx
Public property Configuration Gets or sets the HttpConfiguration of the current ApiController.
Public property ControllerContext Gets the HttpControllerContext of the current ApiController.
Public property ModelState Gets the model state after the model binding process.
Public property Request Gets or sets the HttpRequestMessage of the current ApiController.
Public property Url Returns an instance of a UrlHelper, which is used to generate URLs to other APIs.
Public property User Returns the current principal associated with this request.
*/
base.Initialize(controllerContext);
bool iDontLikeYou = true; /* Your rules here */
if (iDontLikeYou)
{
throw new HttpResponseException(new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.NotFound));
}
}
}
public class ProductsController : EnforceMyBusinessRulesController
{
protected override void Initialize(System.Web.Http.Controllers.HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
}
}
I've been working on a module for IIS7. I want to intercept requests from a specific browser. This is only in dev, but right now my code looks like this:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace MyNamespace
{
class MyModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(OnPreRequestHandlerExecute);
}
#endregion
public void OnPreRequestHandlerExecute(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpRequest request = app.Context.Request;
string useragent = "AGENT: " + request.Headers["User-Agent"];
throw new HttpException(403, useragent);
// stuff here
}
}
}
I want to test this, but despite reading NUMEROUS articles on adding it to IIS7, I can't seem to get it working.
Examples:
http://learn.iis.net/page.aspx/366/developing-iis-70-modules-and-handlers-with-the-net-framework/
http://learn.iis.net/page.aspx/269/how-to-create-a-simple-iis-manager-module/
I've got the module strongly named, signed, you name it. I can't seem to get it to show up under Managed Modules for IIS.
If someone who has experience in this area could point me in the right direction I would greatly appreciate it! The code is very incomplete and I don't expect it to be perfect, but just to get it working under IIS7 right now would be a huge step forward.
Thanks!
You can simply drop the MyNameSpace.dll file in the bin folder, and then reference it like this in the section of the web.config:
<add name="MyModuleName" type="MyNamespace.MyModule, MyNamespace" preCondition="managedHandler" />
How can I have a view render a partial (user control) from a different folder?
With preview 3 I used to call RenderUserControl with the complete path, but whith upgrading to preview 5 this is not possible anymore.
Instead we got the RenderPartial method, but it's not offering me the functionality I'm looking for.
Just include the path to the view, with the file extension.
Razor:
#Html.Partial("~/Views/AnotherFolder/Messages.cshtml", ViewData.Model.Successes)
ASP.NET engine:
<% Html.RenderPartial("~/Views/AnotherFolder/Messages.ascx", ViewData.Model.Successes); %>
If that isn't your issue, could you please include your code that used to work with the RenderUserControl?
In my case I was using MvcMailer (https://github.com/smsohan/MvcMailer) and wanted to access a partial view from another folder, that wasn't in "Shared." The above solutions didn't work, but using a relative path did.
#Html.Partial("../MyViewFolder/Partials/_PartialView", Model.MyObject)
If you are using this other path a lot of the time you can fix this permanently without having to specify the path all of the time. By default, it is checking for partial views in the View folder and in the Shared folder. But say you want to add one.
Add a class to your Models folder:
public class NewViewEngine : RazorViewEngine {
private static readonly string[] NEW_PARTIAL_VIEW_FORMATS = new[] {
"~/Views/Foo/{0}.cshtml",
"~/Views/Shared/Bar/{0}.cshtml"
};
public NewViewEngine() {
// Keep existing locations in sync
base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(NEW_PARTIAL_VIEW_FORMATS).ToArray();
}
}
Then in your Global.asax.cs file, add the following line:
ViewEngines.Engines.Add(new NewViewEngine());
For readers using ASP.NET Core 2.1 or later and wanting to use Partial Tag Helper syntax, try this:
<partial name="~/Views/Folder/_PartialName.cshtml" />
The tilde (~) is optional.
The information at https://learn.microsoft.com/en-us/aspnet/core/mvc/views/partial?view=aspnetcore-3.1#partial-tag-helper is helpful too.
For a user control named myPartial.ascx located at Views/Account folder write like this:
<%Html.RenderPartial("~/Views/Account/myPartial.ascx");%>
I've created a workaround that seems to be working pretty well. I found the need to switch to the context of a different controller for action name lookup, view lookup, etc. To implement this, I created a new extension method for HtmlHelper:
public static IDisposable ControllerContextRegion(
this HtmlHelper html,
string controllerName)
{
return new ControllerContextRegion(html.ViewContext.RouteData, controllerName);
}
ControllerContextRegion is defined as:
internal class ControllerContextRegion : IDisposable
{
private readonly RouteData routeData;
private readonly string previousControllerName;
public ControllerContextRegion(RouteData routeData, string controllerName)
{
this.routeData = routeData;
this.previousControllerName = routeData.GetRequiredString("controller");
this.SetControllerName(controllerName);
}
public void Dispose()
{
this.SetControllerName(this.previousControllerName);
}
private void SetControllerName(string controllerName)
{
this.routeData.Values["controller"] = controllerName;
}
}
The way this is used within a view is as follows:
#using (Html.ControllerContextRegion("Foo")) {
// Html.Action, Html.Partial, etc. now looks things up as though
// FooController was our controller.
}
There may be unwanted side effects for this if your code requires the controller route component to not change, but in our code so far, there doesn't seem to be any negatives to this approach.
The VirtualPathProviderViewEngine, on which the WebFormsViewEngine is based, is supposed to support the "~" and "/" characters at the front of the path so your examples above should work.
I noticed your examples use the path "~/Account/myPartial.ascx", but you mentioned that your user control is in the Views/Account folder. Have you tried
<%Html.RenderPartial("~/Views/Account/myPartial.ascx");%>
or is that just a typo in your question?
you should try this
~/Views/Shared/parts/UMFview.ascx
place the ~/Views/ before your code
Create a Custom View Engine and have a method that returns a ViewEngineResult
In this example you just overwrite the _options.ViewLocationFormats and add your folder directory
:
public ViewEngineResult FindView(ActionContext context, string viewName, bool isMainPage)
{
var controllerName = context.GetNormalizedRouteValue(CONTROLLER_KEY);
var areaName = context.GetNormalizedRouteValue(AREA_KEY);
var checkedLocations = new List<string>();
foreach (var location in _options.ViewLocationFormats)
{
var view = string.Format(location, viewName, controllerName);
if (File.Exists(view))
{
return ViewEngineResult.Found("Default", new View(view, _ViewRendering));
}
checkedLocations.Add(view);
}
return ViewEngineResult.NotFound(viewName, checkedLocations);
}
Example: https://github.com/AspNetMonsters/pugzor
Try using RenderAction("myPartial","Account");