Why does this ViewResult fail MSpecMVC's ShouldBeAView assertion? - asp.net-mvc

I've been following James Broome's tutorial to teach myself MSpec and some of the related infrastructure. I'm using the latest version of MSpec, MSpecMvc, and ASP.NET MVC 2 and I'm not using J.P Boodhoo's libraries.
When I run this test
[Subject(typeof(HomeController))]
public class when_the_home_controller_is_told_to_display_the_default_view
{
static string key;
static string message;
static ActionResult result;
static HomeController home_controller;
Establish context = () =>
{
key = "Message";
message = "Welcome to ASP.NET MVC!";
home_controller = new HomeController();
};
Because of = () => result = home_controller.Index();
It should_return_the_home_view = () => result.ShouldBeAView().And().ViewName.ShouldBeEmpty();
}
I get the following error
should return the home view : Failed
Should be of type System.Web.Mvc.ViewResult but is of type System.Web.Mvc.ViewResult
When I step through the code it conks in the assertion in this method (in the ActionResultExtensions.cs file of MSpecMVC)
public static ViewResultAnd ShouldBeAView(this ActionResult actionResult)
{
actionResult.ShouldBeOfType<ViewResult>();
return new ViewResultAnd(actionResult as ViewResult);
}
Although, I can confirm that actionResult is of type System.Web.Mvc.ViewResult. I've used the same tools on another computer to run other tests but I've not encountered the current issue.

James Broome's MSpec.MVC extensions use Mspec v0.2. Since you are using Mspec v0.3 there is a mismatch. You should get the source and update the solution to use MSpec v0.3.
Make sure the Mspec.MVC extensions target the same .NET Framwork version as your ASP.NET MVC solution (for example, both are 4.0). That will also depend on which version of MSpec you are using. MSpec v0.3 is compiled against both .NET 3.5 and .NET 4.0

Related

Trying to add AutoMapper to Asp.net Core 2?

I worked on a asp.net core 1.1 project a while ago and use in projetc AutoMapper.
in asp.net core 1.1, I add services.AddAutoMapper() in startup file :
StartUp file in asp.net core 1.1:
public void ConfigureServices(IServiceCollection services)
{
//Some Code
services.AddMvc();
services.AddAutoMapper();
}
And I use AutoMapper in Controller easily.
Controller :
public async Task<IActionResult> AddEditBook(AddEditBookViewModel model)
{
Book bookmodel = AutoMapper.Mapper.Map<AddEditBookViewModel, Book>(model);
context.books.Add(bookmodel);
context.SaveChanges();
}
And everything was fine.
But I'm currently working on a Asp.net Core 2 project and I get the error with services.AddAutoMapper() in sturtap file.
Error CS0121 The call is ambiguous between the following methods or properties: 'ServiceCollectionExtensions.AddAutoMapper(IServiceCollection, params Assembly[])' and 'ServiceCollectionExtensions.AddAutoMapper(IServiceCollection, params Type[])'
What is the reason for this error?
Also, services.AddAutoMapper in asp.net core 2 has some parameters. what should I send to this parameter?
If you are using AspNet Core 2.2 and AutoMapper.Extensions.Microsoft.DependencyInjection v6.1
You need to use in Startup file
services.AddAutoMapper(typeof(Startup));
You likely updated your ASP.NET Core dependencies, but still using outdated AutoMapper.Extensions.Microsoft.DependencyInjection package.
For ASP.NET Core you need at least Version 3.0.1 from https://www.nuget.org/packages/AutoMapper.Extensions.Microsoft.DependencyInjection/3.0.1
Which references AutoMapper 6.1.1 or higher.
AutoMapper (>= 6.1.1)
Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.0.0)
Microsoft.Extensions.DependencyModel (>= 2.0.0)
The older packages depend on Microsoft.Extensions.DependencyInjection.Abstractions 1.1.0 and can't be used with ASP.NET Core since there have been breaking changes between Microsoft.Extensions.DependencyInjection.Abstractions 1.1.0 and 2.0
In new version (6.1) of AutoMapper.Extensions.Microsoft.DependencyInjection nuget package you should use it as follows:
services.AddAutoMapper(Type assemblyTypeToSearch);
// OR
services.AddAutoMapper(params Type[] assemblyTypesToSearch);
e.g:
services.AddAutoMapper(typeOf(yourClass));
Install package:
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection -Version 7.0.0
Nuget:
https://www.nuget.org/packages/AutoMapper.Extensions.Microsoft.DependencyInjection/
In Startup Class:
services.AddAutoMapper(typeof(Startup));
None of these worked for me, I have a .NET Core 2.2 project and the complete code for configuring the mapper looks like this(part of ConfigureService() method):
// Auto Mapper Configurations
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new SimpleMappings());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
Then I have my Mappings class which I've placed in the BL project:
public class SimpleMappings : Profile
{
public SimpleMappings()
{
CreateMap<DwUser, DwUserDto>();
CreateMap<DwOrganization, DwOrganizationDto>();
}
}
And finally the usage of the mapper looks like this:
public class DwUserService : IDwUserService
{
private readonly IDwUserRepository _dwUserRepository;
private readonly IMapper _mapper;
public DwUserService(IDwUserRepository dwUserRepository, IMapper mapper)
{
_dwUserRepository = dwUserRepository;
_mapper = mapper;
}
public async Task<DwUserDto> GetByUsernameAndOrgAsync(string username, string org)
{
var dwUser = await _dwUserRepository.GetByUsernameAndOrgAsync(username, org).ConfigureAwait(false);
var dwUserDto = _mapper.Map<DwUserDto>(dwUser);
return dwUserDto;
}
}
Here is a similar link on the same topic:
How to setup Automapper in ASP.NET Core
If you are using AspNet Core 2.2.Try changing your code
from:
services.AddAutoMapper();
to:
services.AddAutoMapper(typeof(Startup));
It worked for me.
In .Net 6, you can do it like
builder.Services.AddAutoMapper(typeof(Program).Assembly); // Since there is no Startup file
OR
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
Basically, it requires the assembly name as shown in screenshot below
I solved this by creating a class that inherits AutoMapper.Profile
public class model_to_resource_profile : Profile
{
public model_to_resource_profile()
{
CreateMap<your_model_class, your_model_resource_class>();
}
}
And adding this line in the Startup.cs:
services.AddAutoMapper(typeof(model_to_resource_profile ));
try this, works with 2.1 and up, i have not used any previous version so can't tell.
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
The official docs:
https://automapper.readthedocs.io/en/latest/Dependency-injection.html#asp-net-core
You define the configuration using profiles. And then you let
AutoMapper know in what assemblies are those profiles defined by
calling the IServiceCollection extension method AddAutoMapper at
startup:
services.AddAutoMapper(profileAssembly1, profileAssembly2 /*, ...*/);
or marker types:
services.AddAutoMapper(typeof(ProfileTypeFromAssembly1), typeof(ProfileTypeFromAssembly2) /*, ...*/);
If you are having issue with adding your auto mapper, It is better you check through the type and version you added.
If it is not "AutoMapper.Extensions.Microsoft.DependencyInjection", then you won't be able to use "services.AddAutoMapper()".
Sometimes, you might mistakenly add "AutoMapper
Dec 6th 2019 Based upon initial attempt in a pluralsight course Building an API with ASP.NET Core by Shawn Wildermuth. As I got the error "...ambiguous 'ServiceCollectionExtensions.AddAutoMapper(IServiceCollection, params Assembly[])..."
I started researching proper syntax to implement AddAutoMapper in Core 2.2. My NuGet reference is version 7.0.0 After the tutorial had me create the Profile class in my Data repository directory which additionally referenced my model nir weiner & dev-siberia's answers above led me to trying to reference the profile class in the Startup.ConfigureServices() by name:
services.AddAutoMapper(typeof(CampProfile));
the content of the profile class is just a (no pun intended) old school map of the data class and the model in its constructor
this.CreateMap<Camp, CampModel>();
This addressed the poor lack of documentation for this current version.
Respectfully,
ChristianProgrammer

An exception of type 'System.InvalidOperationException' occurred in System.Web.Mvc.dll but was not handled in user code

I had working code on VS 2013 NET4.5. After update (VS 2013, NET 4.5.1) of NuGet packages I got this error
An exception of type 'System.InvalidOperationException' occurred in
System.Web.Mvc.dll but was not handled in user code
Additional information: The given filter instance must implement one
or more of the following filter interfaces: IAuthorizationFilter,
IActionFilter, IResultFilter, IExceptionFilter.
I am sure that I implemented IActionFilter interface, so how can I get error like this and how can I fix it?
FYI:
public class WWWActionFilterAttribute : System.Web.Mvc.ActionFilterAttribute, System.Web.Mvc.IActionFilter
{
public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)
{
System.Uri Address = filterContext.HttpContext.Request.Url;
string[] domains = Address.Host.Split('.');
if (domains.Length == 2)
{
System.UriBuilder AddressBuilder = new System.UriBuilder(Address);
AddressBuilder.Host = string.Format("www.{0}", AddressBuilder.Host);
filterContext.HttpContext.Response.Redirect(AddressBuilder.Uri.AbsoluteUri);
}
else
{
base.OnActionExecuting(filterContext);
}
}
}
Config
public class FilterConfig
{
public static void RegisterGlobalFilters(System.Web.Mvc.GlobalFilterCollection filters)
{
filters.Add(new System.Web.Mvc.HandleErrorAttribute());
filters.Add(new TIKSN.HomeWebsite.Generalization.WWWActionFilterAttribute());
filters.Add(new TIKSN.HomeWebsite.Globalization.LanguageActionFilterAttribute());
}
}
Are we talking about System.Web.Mvc.dll having to have the save version and if so where? If I add this DLL to my domain I can only get up to version 4.0. However I have a version 5.1 in my web API the project with web config file. I really don't understand why I would have to match these versions and why my solution doesn't recognize the highest version if that is why its failing. I believe Visual Studio 2013 Express automatically loaded version 5.1, but I had to get my own for the domain project and that doesn't offer 5.1. One of the worst things about MVC is dependency management.
You are adding a HttpFilter (WebAPI filter) to an MVC Global filter. Your filter should be added to HttpFilterCollection
Add this to filterConfig.cs
public static void RegisterHttpFilters(HttpFilterCollection filters)
{
filters.Add(new WWWActionFilterAttribute());
}
And this to Global.ascx.cs:
FilterConfig.RegisterHttpFilters(GlobalConfiguration.Configuration.Filters);
This was because of web.config file. You have to specify exact version of packages there. Look here
Update
In Web.config all packages are registered and have their name and version pairs. The actual versions and the versions in the Web.config were not matching.

How to update breeze.js library

I could use some guidance on how to manually update between versions of Breeze and it's dependencies. I do not believe I can just update with the NuGet Package Manager.
I have been developing my Single Page App with Breeze, Knockout, WebAPI and so forth. I have been using Breeze version 0.61 and want to upgrade to the latest version so I can take advantage of the ODataActionFilters and not have to parse the Request.QueryString to pull out parameters and filters. For example when I call
var getMachineById(machineId) {
var query = EntityQuery
.from("Machines")
.where("machineId", "eq", machineId);
return manager.executeQuery(query)
.then(function (data) {
do_something_with(data.results);
})
.fail(queryFailed);
}
There has to be a way for Breeze to handle that for me, so I can just do something like this:
[AcceptVerbs("GET")]
public IQueryable<Machine> Machines()
{
return _contextProvider.Context.Machines;
}
instead of
// eg "?$filter=machineId%20eq%205"
[AcceptVerbs("GET")]
public IQueryable<Machine> Machines()
{
IQueryable<Machine> x = _contextProvider.Context.Machines;
List<ODataQueryString> list = null;
string qs = Request.RequestUri.Query.ToString(CultureInfo.CurrentCulture);
list = new ODataQueryStringParser(qs).Parse();
if (list != null)
{
int machineId = int.Parse(list[0].Value); // covert string to an int
x = x.Where(o => o.MachineId == machineId);
}
return x;
}
I notice that the Attribute decoration in the Controller has changed in the Samples. Do I need to change mine too?
namespace PilotPlantBreeze.Controllers
{
[JsonFormatter, ODataActionFilter]
public class BreezeController : ApiController
{
readonly EFContextProvider<PilotPlantDbContext> _contextProvider =
new EFContextProvider<PilotPlantDbContext>();
[AcceptVerbs("GET")]
public string Metadata()
{
return _contextProvider.Metadata();
}
[AcceptVerbs("POST")]
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle);
}
... etc.
}
}
I have my 3rd party libraries in a folder ~\Scripts\lib. If I use the NuGet package manager to update, it puts all the replacements in ~\Scripts. How do I move the files into the lib folder without messing up my Team Foundation Server (Azure) source control?
Are the runtime versions of Antlr3.Runtime.dll, Breeze.WebApi.dll, Irony.dll, Newtonsoft.Json.dll, WebActivator.dll and maybe WebGrease.dll compatible between versions. I bet not. Is there something I have to change in Visual Studio?
Can I just change version entries from the package folder in packages.config?
Thanks.
I think that your best approach would be to remove any existing breeze '.js' files and the webApi and irony.dlls from your project and then simply install the latest breeze nuget package. After installing the nuget package you can go ahead and move the files to other locations within the project to match their "old" locations. I'd do the same for the NewtonSoft nuget package as well, just in case ( breeze will add this back for you). Going forward, you can just update to latest nuget and then move the files.
As you noticed you will also need to replace these attributes
[JsonFormatter, ODataActionFilter]
with this attribute
[BreezeController]
This assumes that you are not running a beta version of ASP.MVC4. I think there are posts in other forums that discuss how to migrate away from the beta.

peverify bugs fixed in .NET 4?

I have VS .NET 2010 installed, and a class library targeting .NET 3.5. The simple C# fragment below generates verifiable IL under .NET 4.0's peverify, but the IL does not verify using .NET 3.5's peverify.
Were there any peverify bugs fixed in this transition?
public static bool IsGenericTypeInstance(this Type typ)
{
return typ.IsGenericType && !typ.IsGenericTypeDefinition;
}
public static IEnumerable<Type> GetAllGenericArguments(this Type type)
{
return type.IsGenericTypeInstance()
? type.GetGenericArguments()
.SelectMany(x => x.IsGenericTypeInstance()
? GetAllGenericArguments(x)
: new[] { x })
: Enumerable.Empty<Type>();
}
The error generated is:
Error 26 [Sasa.dll : Sasa.Types::<GetAllGenericArguments>b__0]
[offset 0x0000001C][found ref 'System.Collections.IEnumerable']
[expected ref 'System.Collections.Generic.IEnumerable`1[System.Type]']
Unexpected type on the stack.
I'm obviously a little concerned since I'm explicitly targeting .NET 3.5, and I don't want runtime verification errors on this platform.

Cannot get assembly version for footer

I'm using the automatic build versioning mentioned in this question (not the selected answer but the answer that uses the [assembly: AssemblyVersion("1.0.*")] technique). I'm doing this in the footer of my Site.Master file in MVC 2. My code for doing this is as follows:
<div id="footer">
webmaster#foo.com - Copyright © 2005-<%= DateTime.Today.Year.ToString() %>, foo LLC. All Rights Reserved.
- Version: <%= Assembly.GetEntryAssembly().GetName().Version.ToString() %>
</div>
The exception I get is a Object reference not set to an instance of an object because GetEntryAssembly() returns NULL. My other options don't work either. GetCallingAssembly() always returns "4.0.0.0" and GetExecutingAssembly() always returns "0.0.0.0". When I go look at my DLLs, everything is versioning as I would expect. But I cannot figure out how to access it to display in my footer!!
That's because Assembly.GetEntryAssembly() is returning null: there is no "entry" assembly in an ASP.NET site (because the .NET framework is hosted in the w3wp.exe process). Assembly.GetEntryAssembly() is used to get the .exe assembly that you launched from (usually in a console or Windows application)
The reason Assembly.GetAssembly(this.GetType()) is returning an assembly with version "0.0.0.0" is because ASP.NET compiles your Site.Master file into a temporary assembly under your "ASP.NET Temporary Files" folder. this is a reference to the "generated" class.
Assembly.GetExecutingAssembly() is basically the same as Assembly.GetAssembly(this.GetType()) (except it also works when there is no "this" (e.g. in static methods).
The best way would be use explicity use a type that you know exists in the assembly you're after. As an example, I assume your "Site.Master" has a code-behind file that is compiled into the assembly. You can use that instead:
Assembly.GetAssembly(typeof(Site)).GetName().Version.ToString()
(assuming the name of the class is Site)
Just as another solution that people may be interested in, I've concocted these helpers to help with this problem:
public static class HtmlHelperExtensions
{
private static string _CachedCurrentVersionDate;
/// <summary>
/// Return the Current Version from the AssemblyInfo.cs file.
/// </summary>
public static string CurrentVersion(this HtmlHelper helper)
{
try
{
var version = Assembly.GetExecutingAssembly().GetName().Version;
return version.ToString();
}
catch
{
return "?.?.?.?";
}
}
public static string CurrentVersionDate(this HtmlHelper helper)
{
try
{
if (_CachedCurrentVersionDate == null)
{
// Ignores concurrency issues - assuming not locking this is faster than
// locking it, and we don't care if it's set twice to the same value.
var version = Assembly.GetExecutingAssembly().GetName().Version;
var ticksForDays = TimeSpan.TicksPerDay * version.Build; // days since 1 January 2000
var ticksForSeconds = TimeSpan.TicksPerSecond * 2 * version.Revision; // seconds since midnight, (multiply by 2 to get original)
_CachedCurrentVersionDate = new DateTime(2000, 1, 1).Add(new TimeSpan(ticksForDays + ticksForSeconds)).ToString();
}
return _CachedCurrentVersionDate;
}
catch
{
return "Unknown Version Date";
}
}
}
This allows consumption as follows in your footer:
Version: <%= Html.CurrentVersion() %> from <%= Html.CurrentVersionDate() %>
You can:
e.g in your Application_Start method in Global.asax file add
protected void Application_Start(object sender, EventArgs e)
{
HttpContext.Current.Application.Add("Version", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString());
}
in HTML show it by
<div><% =HttpContext.Current.Application["Version"].ToString() %></div>
ALSO Change Assembly version to 1.0.0.* by going to
- Project properties > Application > Assembly Information and assembly version is shown as 1.0.0.0 - change it to 1.0.0.*
this will give you some versioning
If you already have Global.asax in place, it could be a good place to store version globally once.
Global.asax.cs:
public class Global : HttpApplication
{
public static readonly Version Version = Assembly.GetExecutingAssembly().GetName().Version;
}
Your view:
<div>- Version: #YourNamespace.Global.Version</div>

Resources