I have a UserController that has a Destroy function. It is a rather complex function because it demands to destroy all user's data. I have another action, from the Admin panel that deletes all data from a specific set of users.
Since I don't want to replicate the code from the UserController, I would like to call the Destroy function from UserController for each User to destroy its data.
How should I proceed?
Thanks in advance.
Why not move this functionality to a common class method which can be accessed from both the controllers as needed ?
public class UserManager
{
public void Destroy(List<int> userIdsToDestroy)
{
foreach(var userId in userIdsToDestroy)
{
//Execute code to destroy
}
}
}
and from your action methods, you can call it like
var mgr = new UserManager();
var badUsers = new List<int> { 1,2,3};
mgr.Destroy(badUsers);
Update the badUsers variable value as needed based on from where you are calling it.
Shared functionality like this would ideally be in a business layer, and both controllers would call that code. If it's a little app, you could just create a separate folder structure for shared code. Larger projects would have a business layer dll.
Why not make the Destroy() method as a Non-Action method then like
[Non-Action]
public void Destroy(User user)
{
// code goes here
}
You can as well make this Destroy() function as part of your business layer logic instead of handling this in controller. In that case, you call it from anywhere.
If you want it to be #controller, you can as well consider usig [ChildActionOnly] action filter attribute.
Related
In UWP, I would programmatically initialize display variables at startup so that the initial display was what I wanted, for example, values based on the day of the year value. I can't crack where to replicate this in my otherwise working Blazor webassembly app. I currently put up default values and ask the user to click a button, that calculates and updates to the values I want to display and on we go.
I would have thought there's a standard, easy way to do this, but given how Blazor pieces are constructed on the fly in order to render as web pages, maybe not? Thanks!
This isn't specific to Blazor, but in any class you can create code in the constructor of your component/
Here I have a Chat component, that I break up into
Chat.razor
Chat.razor.cs
The chat.razor.cs you create by adding a class with the same name as your component, then add the word partial to make it a partial class:
partial class Chat : IBlazorComponent, IBlazorComponentParent, IDisposable
Note: The interfaces are just for my app, I am just showing the line with partial.
really are you need it:
partial class Chat
Then in my constructor I created:
public Chat()
{
// Perform initializations for this object
Init();
}
I just call a method, you don't have to:
My Init method:
public void Init()
{
// do your initializations
}
Or you can use OnInitializedAsync
protected override async Task OnInitializedAsync()
{
// load the Categories (example)
this.Categories = await HelpCategoryService.GetHelpCategoryList()
}
Or here is another I use sometimes: OnAfterRender
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
...
}
}
Documentation for that is here:
https://learn.microsoft.com/en-us/aspnet/core/blazor/lifecycle?view=aspnetcore-3.1
Maybe that gives you some ideas. Not sure about Standard, every use case is different.
Note: I have never used Blazor Web Assembly, only server side Blazor, so not sure what is specific to WASM, but I know constructors work in any C# class.
I assume you want to have global Variables for your app:
Create a Initialize service that initializes your static data.
public class InitializeService
{
public InitializeService()
{
MyStaticDataClass.Variable1 == "Pling";
MyStaticDataClass.Variable1 == "GlobalPlong";
}
}
In startup services.AddSingleton().
Your MyStaticDataClass vars will now be available from your app and pages
I'm using a masterpage in my ASP.NET MVC project. This masterpage expects some ViewData to be present, which displays this on every page.
If I don't set this ViewData key in my controllers, I get an error that it can't find it. However, I don't want to set the ViewData in every controller (I don't want to say ViewData["foo"] = GetFoo(); in every controller).
So, I was thinking of setting this in a base controller, and have every controller inherit from this base controller. In the base controller default constructur, I set the ViewData. I found a similar approach here: http://www.asp.net/learn/MVC/tutorial-13-cs.aspx. So far so good, this works... but the problem is that this data comes from a database somewhere.
Now when I want to Unit Test my controllers, the ones that inherit from the base controller call its default constructor. In the default constructor, I initialize my repository class to get this data from the database. Result: my unit tests fail, since it can't access the data (and I certainly don't want them to access this data).
I also don't want to pass the correct Repository (or DataContext, whatever you name it) class to every controller which in turn pass it to the default controller, which I could then mock with my unit tests. The controllers in turn rely on other repository classes, and I would end up passing multiple parameters to the constructor. Too much work for my feeling, or am I wrong? Is there another solution?
I've tried using StructureMap but in the end I didn't feel like that is going to fix my problem, since every controller will still have to call the base constructor which will initialize the repository class, so I can't mock it.
This is a similar question but I find no satisfactory answer was given. Can I solve this in a neat way, maybe using StructureMap as a solution? Or should I jsut suck it and pass a Repository to every controller and pass it again to the base controller? Again, It feels like so much work for something so simple. Thanks!
I see two options:
First:
Set the ViewData for MasterPage in YourBaseController.OnActionExecuting() or YourBaseController.OnActionExecuted():
public class YourBaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Optional: Work only for GET request
if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")
return;
// Optional: Do not work with AjaxRequests
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
return;
...
filterContext.Controller.ViewData["foo"] = ...
}
}
Second:
Or create custom filter:
public class DataForMasterPageAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Optional: Work only for GET request
if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")
return;
// Optional: Do not work with AjaxRequests
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
return;
...
filterContext.Controller.ViewData["foo"] = ...
}
}
and then apply to your controllers:
[DataForMasterPage]
public class YourController : YourBaseController
{
...
}
I think the second solution is exactly for your case.
I've been getting several errors:
cannot add an entity with a key that is already in use
An attempt has been made to attach or add an entity that is not new, perhaps having been loaded from another datacontext
In case 1, this stems from trying to set the key for an entity versus the entity. In case 2, I'm not attaching an entity but I am doing this:
MyParent.Child = EntityFromOtherDataContext;
I've been using using the pattern of wrap everything with a using datacontext. In my case, I am using this in a web forms scenario, and obviously moving the datacontext object to a class wide member variables solves this.
My questions are thus 2 fold:
How can I get rid of these errors and not have to structure my program in an odd way or pass the datacontext around while keeping the local-wrap pattern? I assume I could make another hit to the database but that seems very inefficient.
Would most people recommend that moving the datacontext to the class wide scope is desirable for web pages?
Linq to SQL is not adapted to disconnected scenarios. You can copy your entity to a DTO having a similar structure as the entity and then pass it around. Then copy the properties back to an entity when it's time to attach it to a new data context. You can also deserialize/reserialize the entity before attaching to a new data context to have a clean state. The first workaround clearly violates the DRY principle whereas the second is just ugly. If you don't want to use any of these solution the only option left is to retrieve the entity you're about to modify by its PK by hitting the DB. That means an extra query before every update. Or use another ORM if that's an option for you. Entity Framework 4 (included with .NET 4) with self-tracking entities is what I'm using currently on a web forms project and everything is great so far.
DataContext is not thread-safe and should only be used with using at the method level, as you already do. You can consider adding a lock to a static data context but that means no concurrent access to the database. Plus you'll get entities accumulated in memory inside the context that will turn into potential problems.
For those that came after me, I'll provide my own take:
The error "an attempt has been made to add or attach an entity that is not new" stems from this operation:
Child.Parent = ParentEntityFromOtherDataContext
We can reload the object using the current datacontext to avoid the problem in this way:
Child.Parent = dc.Entries.Select(t => t).Where(t => t.ID == parentEntry.ID).SingleOrDefault();
Or one could do this
MySubroutine(DataContext previousDataContext)
{
work...
}
Or in a web forms scenario, I am leaning to making the DataContext a class member such as this:
DataContext _dc = new DataContext();
Yes, the datacontext is suppose to represent a unit of work. But, it is a light-weight object and in a web forms scenario where a page is fairly transient, the pattern can be changed from the (using dc = new dc()) to simply using the member variable _dc. I am leaning to this last solution because it will hit the database less and require less code.
But, are there gotchas to even this solution? I'm thinking along the lines of some stale data being cached.
What I usually do is this
public abstract class BaseRepository : IDisposable
{
public BaseRepository():
this(new MyDataContext( ConfigurationManager.ConnectionStrings["myConnection"].ConnectionString))
{
}
public BaseRepository(MyDataContext dataContext)
{
this.DataContext = dataContext;
}
public MyDataContext DataContext {get; set;}
public void Dispose()
{
this.DataContext.Dispose();
}
}
Then imagine I have the following repository
public class EmployeeRepository : BaseRepository
{
public EmployeeRepository():base()
{
}
public EmployeeRepository(MyDataContext dataContext):base(dataContext)
{
}
public Employee SelectById(Guid id)
{
return this.DataContext.Employees.FirstOrDefault(e=>e.Id==id);
}
public void Update(Employee employee)
{
Employee original = this.Select(employee.Id);
if(original!=null)
{
original.Name = employee.Name;
//others
this.DataContext.SubmitChanges();
}
}
}
And in my controllers (I am using asp.net mvc)
public ActionResult Update(Employee employee)
{
using(EmployeeRepository employeeRepository = new EmployeeRepository())
{
if(ModelState.IsValid)
{
employeeRepository.Update(employee);
}
}
//other treatment
}
So the datacontext is properly disposed and I can use it across the same instance of my employee repository
Now imagine that for a specific action I want the employee's company to be loaded (in order to be displyed in my view later), I can do this:
public ActionResult Select(Guid id)
{
using(EmployeeRepository employeeRepository = new EmployeeRepository())
{
//Specifying special load options for this specific action:
DataLoadOptions options = new DataLaodOptions();
options.LoadWith<Employee>(e=>e.Company);
employeeRepository.DataContext.LoadOptions = options;
return View(employeeRepository.SelectById(id));
}
}
I have a member class that returned IQueryable from a data context
public static IQueryable<TB_Country> GetCountriesQ()
{
IQueryable<TB_Country> country;
Bn_Master_DataDataContext db = new Bn_Master_DataDataContext();
country = db.TB_Countries
.OrderBy(o => o.CountryName);
return country;
}
As you can see I don't delete the data context after usage. Because if I delete it, the code that call this method cannot use the IQueryable (perhaps because of deferred execution?). How to force immediate execution to this method? So I can dispose the data context..
Thank you :D
The example given by Codeka is correct, and I would advice writing your code with this when the method is called by the presentation layer. However, disposing DataContext classes is a bit tricky, so I like to add something about this.
The domain objects generated by LINQ to SQL (in your case the TB_Countries class) often contain a reference to the DataContext class. This internal reference is needed for lazy loading. When you access for instance list of referenced objects (say for instance: TB_Country.States) LINQ to SQL will query the database for you. This will also happen with lazy loaded columns.
When you dispose the DataContext, you prevent it from being used again. Therefore, when you return a set of objects as you've done in your example, it is impossible to call the States property on a TB_Country instance, because it will throw a ObjectDisposedException.
This does not mean that you shouldn't dispose the DataContext, because I believe you should. How you should solve this depends a bit on the architecture you choose, but IMO you basically got two options:
Option 1. Supply a DataContext to the GetCountriesQ method.
You normally want to do this when your method is an internal method in your business layer and it is part of a bigger (business) transaction. When you supply a DataContext from the outside, it is created outside of the scope of the method and it shouldn't dispose it. You can dispose it at a higher layer. In that situation your method basically looks like this:
public static IQueryable<TB_Country> GetCountriesQ(
Bn_Master_DataDataContext db)
{
return db.TB_Countries.OrderBy(o => o.CountryName);
}
Option 2. Don't return any domain objects from the GetCountriesQ method.
This solution is useful when the method is a public in your business layer and will be called by the presentation layer. You can wrap the data in a specially crafted object (a DTO) that contains only data and no hidden references to the DataContext. This way you have full control over the communication with the database and you can dispose the DataContext as you should. I've written more about his on SO here. In that situation your method basically looks like this:
public static CountryDTO[] GetCountriesQ()
{
using (var db = new Bn_Master_DataDataContext())
{
var countries;
from country in db.TB_Countries
orderby country.CountryName
select new CountryDTO()
{
Name = country.CountryName,
States = (
from state in country.States
order by state.Name
select state.Name).ToList();
};
return countries.ToArray();
}
}
public class CountryDTO
{
public string Name { get; set; }
public List<StateDTO> States { get; set; }
}
As you will read here there are some smart things you can do that make using DTOs less painful.
I hope this helps.
You can convert the queryable to a list, like so:
public static List<TB_Country> GetCountriesQ()
{
using(var db = new Bn_Master_DataDataContext())
{
return db.TB_Countries
.OrderBy(o => o.CountryName).ToList();
}
}
i have a HttpModule that creates an CommunityPrincipal (implements IPrincipal interface) object on every request. I want to somehow store the object for every request soo i can get it whenever i need it without having to do a cast or create it again.
Basically i want to mimic the way the FormsAuthenticationModule works.
It assigns the HttpContext.User property an object which implements the IPrincipal interface, on every request.
I somehow want to be able to call etc. HttpContext.MySpecialUser (or MySpecialContext.MySpecialUser - could create static class) which will return my object (the specific type).
I could use a extension method but i dont know how to store the object so it can be accessed during the request.
How can this be achieved ?
Please notice i want to store it as the specific type (CommunityPrincipal - not just as an object).
It should of course only be available for the current request being processed and not shared with all other threads/requests.
Right now i assign my CommunityPrincipal object to the HttpContext.User in the HttpModule, but it requires me to do a cast everytime i need to use properties on the CommunityPrincipal object which isnt defined in the IPrincipal interface.
I'd recommend you stay away from coupling your data to the thread itself. You have no control over how asp.net uses threads now or in the future.
The data is very much tied to the request context so it should be defined, live, and die along with the context. That is just the right place to put it, and instantiating the object in an HttpModule is also appropriate.
The cast really shouldn't be much of a problem, but if you want to get away from that I'd highly recommend an extension method for HttpContext for this... this is exactly the kind of situation that extension methods are designed to handle.
Here is how I'd implement it:
Create a static class to put the extension method:
public static class ContextExtensions
{
public static CommunityPrinciple GetCommunityPrinciple(this HttpContext context)
{
if(HttpContext.Current.Items["CommunityPrinciple"] != null)
{
return HttpContext.Current.Items["CommunityPrinciple"] as CommunityPrinciple;
}
}
}
In your HttpModule just put the principal into the context items collection like:
HttpContext.Current.Items.Add("CommunityPrincipal", MyCommunityPrincipal);
This keeps the regular context's user property in the natural state so that 3rd party code, framework code, and anything else you write isn't at risk from you having tampered with the normal IPrincipal stroed there. The instance exists only during the user's request for which it is valid. And best of all, the method is available to code as if it were just any regular HttpContext member.... and no cast needed.
Assigning your custom principal to Context.User is correct. Hopefully you're doing it in Application_AuthenticateRequest.
Coming to your question, do you only access the user object from ASPX pages? If so you could implement a custom base page that contains the cast for you.
public class CommunityBasePage : Page
{
new CommunityPrincipal User
{
get { return base.User as CommunityPrincipal; }
}
}
Then make your pages inherit from CommunityBasePage and you'll be able to get to all your properties from this.User.
Since you already storing the object in the HttpContext.User property all you really need to acheive you goal is a Static method that acheives your goal:-
public static class MySpecialContext
{
public static CommunityPrinciple Community
{
get
{
return (CommunityPrinciple)HttpContext.Current.User;
}
}
}
Now you can get the CommunityPrinciple as:-
var x = MySpecialContext.Community;
However it seems a lot of effort to got to avoid:-
var x = (CommunityPrinciple)Context.User;
An alternative would be an Extension method on HttpContext:-
public static class HttpContextExtensions
{
public static CommunityPrinciple GetCommunity(this HttpContext o)
{
return (CommunityPrinciple)o.User;
}
}
The use it:-
var x = Context.GetCommunity();
That's quite tidy but will require you to remember to include the namespace where the extensions class is defined in the using list in each file the needs it.
Edit:
Lets assume for the moment that you have some really good reason why even a cast performed inside called code as above is still unacceptable (BTW, I'd be really interested to understand what circumstance leads you to this conclusion).
Yet another alternative is a ThreadStatic field:-
public class MyModule : IHttpModule
{
[ThreadStatic]
private static CommunityPrinciple _threadCommunity;
public static CommunityPrinciple Community
{
get
{
return _threadCommunity;
}
}
// Place here your original module code but instead of (or as well as) assigning
// the Context.User store in _threadCommunity.
// Also at the appropriate point in the request lifecyle null the _threadCommunity
}
A field decorated with [ThreadStatic] will have one instance of storage per thread. Hence multiple threads can modify and read _threadCommunity but each will operate on their specific instance of the field.