ASP.NET MVC 2 RouteLink method - asp.net-mvc-2

I'm new to ASP.NET MVC and can't figure this out. Working through the Nerdinner example from Professional ASP.NET MVC 2, I copied the PaginatedList helper class and decided to improve it so the forward and back links could be generated by a method within the class instead of writing them out in every view page. I copied this from the view that it was in, Index.aspx:
if (Model.HasPreviousPage)
{
Response.Write(Html.RouteLink("<<<", "Users", new { page=(Model.PageIndex-1) }));
}
And used it to create this method within Helpers\PaginatedList.cs:
public string NavLinks()
{
if (HasPreviousPage)
{
return Html.RouteLink("<<<", "Users", new { page=(PageIndex-1) });
}
}
(HasPreviousPage is a simple method within PaginatedList.)
Straight away it complains that "The name 'Html' does not exist in the current context, so I modified it to take a parameter:
public string NavLinks(HtmlHelper Html)
Now I get "'System.Web.Mvc.HtmlHelper' does not contain a definition for 'RouteLink' and no extension method 'RouteLink' accepting a first argument of type 'System.Web.Mvc.HtmlHelper' could be found (are you missing a using directive or an assembly reference?)".
According to Microsoft documentation on LinkExtensions.RouteLink method, "In Visual Basic and C#, you can call this method as an instance method on any object of type HtmlHelper". Do they lie?
Help!

If your trying to make this an HtmlHelper just change
public string NavLinks(HtmlHelper Html)
{
if (HasPreviousPage)
{
return Html.RouteLink("<<<", "Users", new { page=(PageIndex-1) });
}
}
to
using System.Web.Mvc;
using System.Web.Mvc.Html;
public static MvcHtmlString NavLinks(this HtmlHelper html, hasPreviousPage)
{
if (hasPreviousPage)
{
return html.RouteLink("<<<", "Users", new { page=(PageIndex-1) });
}
}
All of the HtmlHelpers contained within Mvc are static methods and also they return an MvcHtmlString in Asp.net MVC 2. This will be an extension method for the class HtmlHelper. After adding those references to your code file that contains this extension methods you should see the RouteLink method inside of there.

#DeathBedMotorcade
That helped, but I had to change a few things.
The method can't be static because it needs to access properties of the object (part of same class, PaginatedList), specifically the HasPreviousPage method and the PageIndex variable. Then it gave the error "Extension method must be static". Removing the "this" keyword fixed that. So I have:
public MvcHtmlString NavLinks(HtmlHelper html)
{
if (HasPreviousPage)
{
return html.RouteLink("<<<", "Users", new { page=(PageIndex-1) });
}
if (HasNextPage)
{
return html.RouteLink(">>>", "Users", new { page=(PageIndex+1) });
}
return null;
}
And in the view:
Response.Write(Model.NavLinks(Html))
And that works, though I don't fully understand all the reasons why it didn't before.
"using System.Web.Mvc.Html" was key although I thought I'd tried that at some point; probably before realising the item "Html" (an HtmlHelper object that is implicitly passed to the view?) needed to be passed in. VS usually prompts for missing Using statements but didn't this time.
Thanks.

Related

In Symfony where should I put entity dependant functions

I have this code in my controller, it takes 'procedure_type' from the request and checks to see if a ProcedureType with that name exists. If it does it uses the object, if not it creates a new ProcedureType, then return the new object to use.
// Check the typed in ProcedureType against existing types.
$procedureTypes = $entityManager->getRepository('IncompassSurgeryBundle:ProcedureType')->findBy(array('name' => $request->request->get('procedure_type'), 'vendor' => $vendorId));
if (empty($procedureTypes)) {
// Create Procedure Type
$procedureType = new ProcedureType();
$procedureType->setVendor($vendor)
->setName($request->request->get('procedure_type'))
->setCreated(new \DateTime())
->setUpdated($procedureType->getCreated());
$entityManager->persist($procedureType);
} else {
$procedureType = $procedureTypes[0];
}
I don't think this is the best way to do this, I'd like to move the code into a function, say checkProcedureType(), but I don't know where the best place is to put that. I don't think it could go in the Entity or Repository classes, and moving it to a private function in the controller doesn't feel right.
I'm sure there is a class type that I'm not aware of, that extends the Entity. Or maybe I should just put these functions in my entity classes.
Service are the answer to almost everything in Symfony 2. Create a service like this :
namespace Your\Bundle\Service;
class ProcedureService // Call this the way you want
{
protected $entityManager;
public function __construct($entityManager)
{
$this->entityManager = $entityManager;
}
public function callMeTheWayYouWant($vendorId, $vendor)
{
// Check the typed in ProcedureType against existing types.
$procedureTypes = $this->entityManager->getRepository('IncompassSurgeryBundle:ProcedureType')->findBy(array('name' => $request->request->get('procedure_type'), 'vendor' => $vendorId));
if (empty($procedureTypes)) {
// Create Procedure Type
$procedureType = new ProcedureType();
$procedureType->setVendor($vendor)
->setName($request->request->get('procedure_type'))
->setCreated(new \DateTime())
->setUpdated($procedureType->getCreated());
$this->entityManager->persist($procedureType);
} else {
$procedureType = $procedureTypes[0];
}
// The rest of your code
}
}
In your services.yml file :
your_service:
class: Your\Bundle\Service\ProcedureService
arguments: [#doctrine.orm.entity_manager]
Then use it in your controller :
$this->get('your_service')->callMeTheWayYouWant($vendorId, $vendor);
If logic is somehow related to acessing database I always go for repository. However, if cases like yours, I tend to analyze it's dependency map.
Does your code repeats in some other method within same class, only?
If so, go for private method.
Is this part of code reused somewhere else but does not rely on some services?
You could externalize logic by creating separate class and static method which executes the code. Beware: Tends to get messy really quick
Finally, does your code rely on services/configuration?
Create a separate service, inject the services/configuration and invoke it's method. Adds a bit of overhead, if your abuse it, but you should be fine
Personally, in your example, I would go for private method, but that's just my opinion.

How do I get to use Model1.foo instead of Model1.edmx, and invoke IModelConversionExtension callbacks

I have a VSIX and a associated MEF DLL using IModelConversionExtension Class as per the documentation, and a pkgdef file setting up .foo as an extension to invoke the EF Designer.
[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(IModelConversionExtension))]
[ModelFileExtension(".foo")]
public class MyConversionCallback : IModelConversionExtension
{
public void OnAfterFileLoaded(ModelConversionExtensionContext context)
{
//How does this get called?
return;
}
public void OnBeforeFileSaved(ModelConversionExtensionContext context)
{
//How does this get called?
return;
}
}
[$RootKey$\Editors\{c99aea30-8e36-4515-b76f-496f5a48a6aa}\Extensions]
"foo"=dword:00000032
[$RootKey$\Projects]
[$RootKey$\Projects\{F184B08F-C81C-45F6-A57F-5ABD9991F28F}]
[$RootKey$\Projects\{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\RelatedFiles]
[$RootKey$\Projects\{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\RelatedFiles\.foo]
".diagram"=dword:00000002
[$RootKey$\Projects]
[$RootKey$\Projects\{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}]
[$RootKey$\Projects\{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\RelatedFiles]
[$RootKey$\Projects\{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\RelatedFiles\.foo]
".diagram"=dword:00000002
I can get both the similar Transform and Generation MEF Classes to work fine.
And my Model1.foo does invoke the EF Designer, but
1. OnAfterFileLoaded and OnBeforeFileSaved never fire, and
2. I get an error message when I try to save Model1.foo, which says to see errors in the Error List but there are none.
What am not doing to get this to work.
Thanks
OnAfterFileLoaded is supposed to be invoked if you load a file whose extension is different than edmx and the IEntityDesignerConversionData.FileExtension returns a value that matches your extension. OnBeforeFileSaved works the opposite way - on save. However - I looked at code in this area today and concluded that it actually cannot work. I filed a work item for this: https://entityframework.codeplex.com/workitem/1371

Dependecy injection of arguments known at runtime?

I've been using IoC container's for quite some time but today I've found some "pattern" appearing in code over and over again. To give you some background I am now working on web application basically used for data analysis. There is a set of features there, that requires user to pick up what we call QueryTypeContex at the very beginning. Once this query type is chosen other steps may be taken but that all are performed in this specific QueryTypeContex. In the gui the QueryTypeContex pick up is represented as opening new tab with other controls.
When user is working with given QueryTypeContex all ajax calls to the server include QueryTypeId that identifies users choice and is used to build QueryTypeContex on the server which then is used for various data retrieval and manipulation.
What I've found is that many of our controllers (we use asp.net mvc) that are constructed with Ioc container have one thing in common. There is an action method that looks somewhat like this:
public class AttributeController : Controller
{
public AttributeController(IUsefulService usefulService)
{
_usefulservice = usefulService;
}
ActionResult GetAttributes(QueryTypeContex context)
{
var dataDto = _usefulService.Manipulate(context, currentUser);
return JSon(dataDto);
}
...
}
In order to bind QueryTypeContex to action argument we use custom model binder that pulls some information from database. Once the service gets QueryTypeContex as argument it passes it or its properties down to its collaborators in method arguments for instance data access layer. And so there is a factory class that looks like this
public interface IDateValueFactory
{
DateValue CurrentYear(QueryTypeContex context);
DateValue RollingMonth(int numberOfMonths, QueryTypeContex context);
DateValue RollingQuareter(int numberOfQuarters, QueryTypeContex context);
}
public class DateValueFactory : IDateValueFactory
{
public DateValueFactory(IDateValueDb dateValueDb)
{
_dateValueDb = dateValueDb;
}
public DateValue CurrentYear(QueryTypeContext context)
{
var currentYear = _dateValueDb.GetCurrentYear(context.Id);
return new DateValue(DateValueType.CurrentYear, currentYear, context);
}
public DateValue RollingMonth(int numberOfMonths, QueryTypeContex context)
{
return new DateValue(DateValueType.RollingMonth, numberOfMonths, context);
}
...
}
As you see all of these methods get QueryTypeContex as a parameter more importantly they all get the very same instance of QueryTypeContex during their short life (one web request). So I started to wonder if I could refactor this so that whenever many service class methods require QueryTypeContex as arguments it would be injected via constructor instead of passing the same value over an over again. For example:
public interface IDateValueFactory
{
DateValue CurrentYear();
DateValue RollingMonth(int numberOfMonths);
DateValue RollingQuareter(int numberOfQuarters);
}
public class DateValueFactory : IDateValueFactory
{
public DateValueFactory(IDateValueDb dateValueDb, QueryTypeContext context)
{
_dateValueDb = dateValueDb;
_context = context;
}
public DateValue CurrentYear()
{
var currentYear = _dateValueDb.GetCurrentYear(_context.Id);
return new DateValue(DateValueType.CurrentYear, currentYear, _context);
}
public DateValue RollingMonth(int numberOfMonths)
{
return new DateValue(DateValueType.RollingMonth, numberOfMonths, _context);
}
...
}
And now the real question:
Is this a good idea to to this sort of thing or it violates some design principles i should adhere to ?
In order to inject QueryTypeContex instance, builded using information from http request I thought about embedding the QueryTypeId in the uris so it would be available in the RouteData on the server. Then before the controller is constructed I could pull it out, build the QueryTypeContex, create nested IoC container for that request and inject it into the container. Then whenever some class would need QueryTypeContex to perform its job it would simply declare it as constructor argument.
Anything you can meaningfully push to the constructor as dependencies, you should. Dependencies wired up with constructor injection are implementation details, whereas method parameters are part of your model's API.
It's much easier to refactor dependencies wired through constructors than to change an API, so for maintainability reasons you should prefer as few method parameters as possible.

How to handle actions and views names in my ASP.NET MVC application?

I have an ASP.NET MVC applications and i don't want to explicitly write the actions or the views names like this :
return RedirectToAction("Index"); or
return View("Home");
what is the best practice for handling those strings?
I use Visual Studio 2010 and ASP.NET MVC2
There's MVCContrib and inside there are extension methods allowing you to write:
return RedirectToAction<HomeController>(x => x.About());
Another possibility is T4 templates.
Use T4MVC. It will allow you to kill all magic strings in your code.
I've created a static class like so:
public static class Routing {
public static RouteValueDictionary Index {
get {
return new RouteValueDictionary {
{ "controller", "Default" },
{ "action", "Index" }
};
}
}
}
so i can use it like this:
return RedirectToAction(Routing.Index);

RIA Services EntitySet does not support 'Edit' operation

Making my first steps in RIA Services (VS2010Beta2) and i encountered this problem:
created an EF Model (no POCOs), generic repository on top of it and a RIA Service(hosted in an ASP.NET MVC application) and tried to get data from within the ASP.NET MVC application: worked well.
Next step: Silverlight client. Got a reference to the RIAService (through its context), queried for all the records of the repository and got them into the SL application as well (using this code sample):
private ObservableCollection<Culture> _cultures = new ObservableCollection<Culture>();
public ObservableCollection<Culture> cultures
{
get { return _cultures; }
set
{
_cultures = value;
RaisePropertyChanged("cultures");
}
}
....
//Get cultures
EntityQuery<Culture> queryCultures = from cu in dsCtxt.GetAllCulturesQuery()
select cu;
loCultures = dsCtxt.Load(queryCultures);
loCultures.Completed += new EventHandler(lo_Completed);
....
void loAnyCulture_Completed(object sender, EventArgs e)
{
ObservableCollection<Culture> temp=
new ObservableCollection<Culture>loAnyCulture.Entities);
AnyCulture = temp[0];
}
The problem is this: whenever i try to edit some data of a record (in this example the first record) i get this error:
This EntitySet of type 'Culture' does not support the 'Edit' operation.
I thought that i did something weird and tried to create an object of type Culture and assign a value to it: it worked well!
What am i missing? Do i have to declare an EntitySet? Do i have to mark it? Do i have to...what?
Thanks in advance
It turns out that in the DomainService class one has to implement (or at least to mark "placeholder methods") as "Edit", "Delete",... eg
[Delete]
public void DeleteCulture(Culture currentCulture)
{
throw new NotImplementedException("UpdateCulture not Implemented yet");
}
[Insert]
public void InsertCulture(Culture newCulture)
{
throw new NotImplementedException("InsertCulture not Implemented yet");
}
This way the OrganizationDomainContextEntityContainer class creates an EntitySet with parameter EntitySetOperations.All (meaning that all the CUD operations are available).
Hope it's useful for someone in the future!