My problem is mocked object doesn't return the value it return null instead
My MSpec UnitTest as follows
public class With_Fake_Data_Service
{
protected static Mock<IMProposalWCFService> _fakeDataService;
protected static FaultContract fault;
private Establish context = () =>
{
_fakeDataService = new Mock<IMProposalWCFService>();
_fakeDataService.Setup(
service =>
service.ReplyToProposal(new ReplyToProposalRequest(Moq.It.IsAny<Proposal>(), Moq.It.IsAny<bool>())))
.Returns(new ReplyToProposalResponse( Moq.It.IsAny<bool>(), fault));
_fakeDataService.Setup(
service => service.ReplyToProposalEmail(new ReplyToProposalEmailRequest(Moq.It.IsAny<string>(), Moq.It.IsAny<bool>())))
.Returns(new ReplyToProposalEmailResponse(Moq.It.IsAny<string>(), fault));
_fakeDataService.Setup(service => service.GetAllProposals(Moq.It.IsAny<GetAllProposalsRequest>()))
.Returns(() => new GetAllProposalsResponse(new List<Proposal>(){new Proposal()}, fault));
_fakeDataService.Setup(service => service.GetAllProposals(Moq.It.IsAny<GetAllProposalsRequest>())).Verifiable();
};
}
public class When_Testing_HomeController_Index : With_Fake_Data_Service
{
protected static HomeController _homeController;
protected static IList<Proposal> _proposals;
private Establish context = () =>
{
_homeController = new HomeController(_fakeDataService.Object);
};
private Because of = () =>
{
var result = _homeController.Index() as ViewResult;
_proposals = result.Model as IList<Proposal>;
};
private It Should_Have_Called_GetAllProposals_At_Least_Once =
() => _fakeDataService.Verify(service => service.GetAllProposals(Moq.It.IsAny<GetAllProposalsRequest>()), Times.Exactly(1));
}
Inside the Actual Code HomeController Index Method I get response as null when running above unit test
public HomeController(IMProposalWCFService service)
{
_service = service;
}
public ActionResult Index()
{
var response = _service.GetAllProposals(new GetAllProposalsRequest());
if (response.fault == null) /*Right Here reponse is null when running unit test*/
{
var proposals = response.GetAllProposalsResult;
}
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
Why am i Not getting not null response in other words why i'm not getting
new GetAllProposalsResponse(new List(){new Proposal()}, fault)
please help
Found the problem its
public class With_Fake_Data_Service
{
protected static Mock<IMProposalWCFService> _fakeDataService;
protected static FaultContract fault;
private Establish context = () =>
{
_fakeDataService = new Mock<IMProposalWCFService>();
_fakeDataService.Setup(
service =>
service.ReplyToProposal(new ReplyToProposalRequest(Moq.It.IsAny<Proposal>(), Moq.It.IsAny<bool>())))
.Returns(new ReplyToProposalResponse( Moq.It.IsAny<bool>(), fault));
_fakeDataService.Setup(
service => service.ReplyToProposalEmail(new ReplyToProposalEmailRequest(Moq.It.IsAny<string>(), Moq.It.IsAny<bool>())))
.Returns(new ReplyToProposalEmailResponse(Moq.It.IsAny<string>(), fault));
_fakeDataService.Setup(service => service.GetAllProposals(Moq.It.IsAny<GetAllProposalsRequest>()))
.Returns(() => new GetAllProposalsResponse(new List<Proposal>(){new Proposal()}, fault)).Verifiable();
};
}
Related
I recently upgraded my app to .net core 6 and now I am getting this error when trying to get a service using this code:
IUnityContainer container = HangfireUnityConfig.GetConfiguredContainer();
var authService = container.Resolve<IAuthService>();
I read some other posts that mentioned adding HttpContextAccessor in my ConfigureServices() method but none of the ways ive tried fixed the error.
services.AddHttpContextAccessor();
services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Another person mentioned adding the line in my Program.cs but still getting the error.
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
If I add RegisterType<IHttpContextAccessor, HttpContextAccessor>() to RegisterTypes() in my HangFireUnityConfig class the error goes away but throws a new error later on so Im not sure if thats the right fix.
public static void RegisterTypes(IUnityContainer container)
{
// register hangfire dependencies
container.RegisterType<IHttpContextAccessor, HttpContextAccessor>()
}
AuthService.cs
using MyApp.Entities.DTOs;
namespace MyApp.Service.Auth
{
public class AuthService : IAuthService
{
private UserDto currentUser = null;
private readonly IHttpContextAccessor _context;
public AuthService(IHttpContextAccessor ctx)
{
_context = ctx;
currentUser = parseClaimsUser();
}
public bool isInRole(string role, List<string> roleList)
{
return true;
}
public UserDto parseClaimsUser()
{
ClaimsPrincipal currentClaim = _context.HttpContext.User;
UserDto parsedUser = new UserDto();
bool isAdmin = false;
if (currentClaim == null || !currentClaim.Identity.IsAuthenticated)
{
return parsedUser;
}
//return user id from token properties
parsedUser.userID = currentClaim.Claims.Where(claim => claim.Type == ClaimTypes.NameIdentifier).Select(v => v.Value).FirstOrDefault<string>();
// retrieve groups from token properties --- this is only retrieved upon login. Users will have to log out and log back in to see any changes in groups
var currentGroupsIDs = currentClaim.HasClaim(claim => claim.Type == ClaimTypes.Role) ?
currentClaim.Claims.Where(t => t.Type == ClaimTypes.Role).Select(y => int.Parse(y.Value)).ToList<int>()
: new List<int>();
var adminString = currentClaim.Claims.Where(claim => claim.Type == ClaimTypes.AuthorizationDecision)
.Select(v => v.Value)
.SingleOrDefault<string>();
adminString = adminString == null ? "False" : adminString;
isAdmin = bool.Parse(adminString);
//parsedUser.userGrp = currentGroups;
parsedUser.userGrpIDs = currentGroupsIDs;
parsedUser.isAuthenticated = currentClaim.Identity.IsAuthenticated;
parsedUser.displayName = currentClaim.Identity.Name;
parsedUser.email = currentClaim.Claims.Where(w => w.Type == ClaimTypes.Email).Select(v => v.Value).SingleOrDefault<string>();
//parsedUser.currentToken = tokenExtract;
parsedUser.isAdmin = isAdmin;
var isUS = currentClaim.Claims.Where(claim => claim.Type == "us_citizen").Select(v => v.Value).SingleOrDefault<string>();
if (isUS != null)
{
parsedUser.isUSCitizenAndJPLEmployee = bool.Parse(isUS);
}
return parsedUser;
}
public void initUser()
{
currentUser = parseClaimsUser();
}
public UserDto getCurrentUser(bool includeToken = false)
{
if (currentUser == null || currentUser.userID == null)
{
currentUser = parseClaimsUser();
}
if (!includeToken)
{
currentUser.currentToken = null;
}
return currentUser;
}
public bool userIsAdmin()
{
return true;
}
}
}
I was able to figure out the error I was getting with my last implementation. The error was with not being able to cast my dbContext to type IObjectContextAdapter.
public List<KeyValuePair<string, long>> GetKeys(EntityEntry entry)
{
var keys = new List<KeyValuePair<string, long>>();
var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);
if (objectStateEntry.EntityKey.EntityKeyValues != null)
{
keys.AddRange(objectStateEntry.EntityKey.EntityKeyValues.Select(key => new KeyValuePair<string, long>(key.Key, Convert.ToInt64(key.Value))));
}
return keys;
}
I refactored the code to look like this and got no errors.
public List<KeyValuePair<string, long>> GetKeys(EntityEntry entry)
{
//this gets an array of the key names
var keyNames = entry.Metadata.FindPrimaryKey()
.Properties
.Select(p => p.Name)
.ToArray();
var keys = new List<KeyValuePair<string, long>>();
if (keyNames != null)
{
//creates the KeyValuePairs
keys.AddRange(keyNames.Select(key => new KeyValuePair<string, long>(key, Convert.ToInt64(entry.Property(key).CurrentValue))));
}
return keys;
}
I am trying to implement IdentityFramework in my .NET Core 6 Web API Application.
Following is my settings.
public class ApplicationUser : IdentityUser<int>
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
My connection string is :
"ConnectionStrings": {
"connectionString": "Server=DESKTOP-HO7FAAD\\SQLEXPRESS; Database=AviaryDB; Trusted_Connection=True; MultipleActiveResultSets=true;"
}
Program.cs
builder.Services.AddIdentity<ApplicationUser, IdentityRole<int>>()
.AddEntityFrameworkStores<ApplicationDBContext>()
.AddDefaultTokenProviders();
builder.Services.AddDbContext<ApplicationDBContext>(db => db.UseSqlServer(builder.Configuration.GetConnectionString("connectionString")));
ApplicationDBContext.cs
public class ApplicationDBContext : IdentityDbContext<ApplicationUser, IdentityRole<int>, int>
{
public ApplicationDBContext(DbContextOptions<ApplicationDBContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(entity =>
{
entity.Property(p => p.Id).ValueGeneratedOnAdd();
entity.Property(p => p.FirstName).HasMaxLength(150);
entity.Property(p => p.LastName).HasMaxLength(150);
entity.ToTable(name: "Users");
});
builder.Entity<IdentityRole<int>>(entity =>
{
entity.Property(p => p.Id).ValueGeneratedOnAdd();
entity.ToTable(name: "Roles");
});
builder.Entity<IdentityUserRole<int>>(entity =>
{
entity.ToTable("UserRoles");
//in case you chagned the TKey type
entity.HasKey(key => new { key.UserId, key.RoleId });
});
builder.Entity<IdentityUserClaim<int>>(entity =>
{
entity.ToTable("UserClaims");
});
builder.Entity<IdentityUserLogin<int>>(entity =>
{
entity.ToTable("UserLogins");
//in case you chagned the TKey type
entity.HasKey(key => new { key.ProviderKey, key.LoginProvider });
});
builder.Entity<IdentityRoleClaim<int>>(entity =>
{
entity.ToTable("RoleClaims");
});
builder.Entity<IdentityUserToken<int>>(entity =>
{
entity.ToTable("UserTokens");
//in case you chagned the TKey type
entity.HasKey(key => new { key.UserId, key.LoginProvider, key.Name });
});
}
}
AccountController.cs
public class AccountController : ControllerBase
{
private readonly UserManager<ApplicationUser> _userManager;
public AccountController(
UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[AllowAnonymous]
[HttpPost]
[Route("register")]
public async Task<ActionResult> Register([FromBody] RegisterModel model)
{
try
{
var userExists = await _userManager.FindByNameAsync(model.Username);
if (userExists != null)
return StatusCode(StatusCodes.Status500InternalServerError, new Response { Status = "Error", Message = "User already exists!" });
ApplicationUser user = new()
{
Email = model.Email,
SecurityStamp = Guid.NewGuid().ToString(),
UserName = model.Username,
};
var result = await _userManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
return StatusCode(StatusCodes.Status500InternalServerError, new Response { Status = "Error", Message = "User creation failed! Please check user details and try again." });
return Ok("User created successfully!");
}
catch(Exception ex)
{
throw ex;
}
}
}
And I am getting the following error. Can anyone guide me what I am doing wrong?
I have created an attribute for action names. I want to get the attribute names in my service. I tried so many solutions but it doesn't return anything.
This is my attribute class:
public class CustomeAttribute : ActionFilterAttribute
{
public string Name { get; set; }
}
This is the action that I used the attribute for:
[Custome(Name ="ُShow courses")]
public IActionResult Index()
{
var course = _courseService.GetAllCourses();
return View(course);
}
This is the method that I want to return the attribute name:
public IList<ActionAndControllerName> AreaAndActionAndControllerNamesList(Assembly asm)
{
var contradistinction = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
.SelectMany(type =>
type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Public))
.Select(x => new
{
Controller = x.DeclaringType?.Name,
//Action = x.Name,
//Action=x.DeclaringType?.GetCustomAttributes(typeof(CustomeAttribute), false),
//
Action=x.DeclaringType?.CustomAttributes.Where(c=>c.AttributeType==typeof(CustomeAttribute)),
// Action=x.DeclaringType?.GetCustomAttributes(typeof(CustomeAttribute), false),
// Action=x.DeclaringType?.CustomAttributes(typeof(CustomeAttribute), false),
//Action=x.DeclaringType?.GetCustomAttribute(typeof(CustomeAttribute), false),
Action=x.DeclaringType?.GetCustomAttributes<CustomeAttribute>(),
//Action = x.DeclaringType?.GetCustomAttributes().Where(a => a.GetType() ==
typeof(CustomeAttribute))
Area = x.DeclaringType?.CustomAttributes.Where(c => c.AttributeType ==
typeof(AreaAttribute)),
});
}
As I said I tried the solutions above that are commented but none of them worked. What should I do?
You can try to save Name to some place in ActionfilterAttribute.Here is a demo to save data to session in OnActionExecuting method:
TestController:
SomeOtherClass _someOtherClass;
public TestController(SomeOtherClass someOtherClass)
{
_someOtherClass = someOtherClass;
}
[Custome(Name = "Show courses")]
public IActionResult TestActionFilterAttribute()
{
var Name = _someOtherClass.TestGet();
return Ok();
}
SomeOtherClass:
public class SomeOtherClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
private ISession _session => _httpContextAccessor.HttpContext.Session;
public SomeOtherClass(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string TestGet()
{
return _session.GetString("Custome_Name");
}
}
Startup.cs(IHttpContextAccessor can help get seesion outside controller):
public void ConfigureServices(IServiceCollection services)
{
...
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromDays(1);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<SomeOtherClass, SomeOtherClass>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
...
}
CustomeAttribute:
public class CustomeAttribute: ActionFilterAttribute
{
public string Name { get; set; }
public override void OnActionExecuting(ActionExecutingContext
context)
{
if (Name != null)
{
context.HttpContext.Session.SetString("Custome_Name", Name);
}
}
public override void OnActionExecuted(ActionExecutedContext
context)
{
}
}
result:
I found the solution.I shouldn't have used "DeclaringType" in service.
This is the solution:
var contradistinction = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
.SelectMany(type =>
type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Public))
.Select(x => new
{
Controller = x.DeclaringType?.Name,
Action = x.GetCustomAttribute<CustomeAttribute>()?.Name,
Area = x.DeclaringType?.CustomAttributes.Where(c => c.AttributeType ==
typeof(AreaAttribute)),
});
I have some asp.net core application.
It uses Bearer authentication.
My auth and SignalR seattings. Also I use OpenIddict.
ConfigureServices
services.AddMvc();
...
services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
{
builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowAnyOrigin()
.AllowCredentials();
}));
//services.AddSignalR();
services.AddSignalR(hubOptions =>
{
hubOptions.EnableDetailedErrors = true;
});
...
services.AddDefaultIdentity<Account>(opt =>
{
opt.Password.RequiredUniqueChars = 1;
opt.Password.RequireNonAlphanumeric = false;
opt.Password.RequireLowercase = false;
opt.Password.RequireDigit = false;
opt.Password.RequireUppercase = false;
opt.Password.RequiredLength = Account.MinPasswordLength;
opt.Lockout.AllowedForNewUsers = false;
opt.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
opt.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
opt.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
})
.AddUserManager<AccountManager>()
.AddRoles<AccountRole>()
.AddEntityFrameworkStores<ApplicationContext>()
.AddDefaultTokenProviders();
services.AddOpenIddict()
.AddCore(opt =>
{
opt.UseEntityFrameworkCore()
.UseDbContext<ApplicationContext>();
})
.AddServer(opt =>
{
opt.SetAccessTokenLifetime(TimeSpan.FromMinutes(5));
opt.UseMvc();
opt.AllowCustomFlow(WebConstants.AdminGrantType)
.EnableTokenEndpoint("/api/common/auth/Token")
.AllowRefreshTokenFlow()
.DisableHttpsRequirement()
.AcceptAnonymousClients();
});
services.AddAuthentication()
.AddOAuthValidation(options =>
{
options.Events.OnRetrieveToken = context =>
{
context.Token = context.Request.Query["access_token"];
return Task.CompletedTask;
};
});
Configure
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseSignalR(routes =>
{
routes.MapHub<SomeHub >("/someHub");
});
AuthAccountTypeAttribute
public class AuthAccountTypeAttribute : AuthorizeAttribute
{
public AuthAccountTypeAttribute(params AccountType[] accountType)
{
if (accountType.Any())
{
Roles = string.Join(',', accountType.Select(x => x.ToString()));
}
AuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme;
}
}
And directly Hub
[AuthAccountType(AccountType.Admin)]
public class SomeHub : Hub
{
private readonly AccountManager _accountManager;
private readonly IUnitOfWork _unitOfWork;
public SomeHub (AccountManager accountManager, IUnitOfWork unitOfWork)
{
_accountManager = accountManager;
_unitOfWork = unitOfWork;
}
public override Task OnConnectedAsync()
{
return base.OnConnectedAsync();
}
public async Task OnConnectSmth()
{
}
}
If you use authorize attribute like this all works fine, but if SomeHub used without AuthAccountType and OnConnectSmth with
[AuthAccountType(AccountType.Admin)]
public async Task OnConnectSmth()
{
}
It returns 401.
What can I do?
SignalR 1.0.4
.Net Core 2.1
The same issue if I use basic Authorize
[Authorize(AuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)]
Or how can I made Anonymous connection in Authorize Hub?
DefaultScheme was not set in ConfigureServices(). And strange rules in Hub.
Fix:
services.AddAuthentication(options => { options.DefaultScheme = OAuthValidationDefaults.AuthenticationScheme; } );
I have these three lines of c# code using Moq, how can I write a single line?
JobQueueRepository.Setup(r => r.UpdateJobQueueStatus(DefaultJobId, JobStatus.Success)).Callback(() => statuses.Add(JobStatus.Success));
JobQueueRepository.Setup(r => r.UpdateJobQueueStatus(DefaultJobId, JobStatus.Failed)).Callback(() => statuses.Add(JobStatus.Failed));
JobQueueRepository.Setup(r => r.UpdateJobQueueStatus(DefaultJobId, JobStatus.Running)).Callback(() => statuses.Add(JobStatus.Running));
Thanks for the help.
There is a piece of code you are asking for
JobQueueRepository
.Setup(it => it.UpdateJobQueueStatus(DefaultJobId, It.IsAny<JobStatus>()))
.Callback<int, JobStatus>((id, status) => statuses.Add(status));
And a test that tests how it works
[TestClass]
public class TestClass
{
[TestMethod]
public void TestMethod()
{
var statuses = new List<JobStatus>();
var JobQueueRepository = new Mock<IJobQueueRepository>();
int DefaultJobId = 100500;
JobQueueRepository
.Setup(it => it.UpdateJobQueueStatus(DefaultJobId, It.IsAny<JobStatus>()))
.Callback<int, JobStatus>((id, status) => statuses.Add(status));
JobQueueRepository.Object.UpdateJobQueueStatus(DefaultJobId, JobStatus.Failed);
JobQueueRepository.Object.UpdateJobQueueStatus(DefaultJobId, JobStatus.Running);
JobQueueRepository.Object.UpdateJobQueueStatus(DefaultJobId, JobStatus.Success);
statuses.Should().HaveCount(3);
statuses.Should().Contain(JobStatus.Failed);
statuses.Should().Contain(JobStatus.Running);
statuses.Should().Contain(JobStatus.Success);
}
public enum JobStatus
{
Success,
Failed,
Running
}
public interface IJobQueueRepository
{
void UpdateJobQueueStatus(int id, JobStatus status);
}
}
You can easily create an extension method to do that as below.
public class Class1
{
[Test]
public void CallBackDemo() {
var statuses = new List<JobStatus>();
var jobQueueRepositoryStub = new Mock<IJobQueueRepository>();
const int defaultJobId = 100500;
jobQueueRepositoryStub.Setup(r => r.UpdateJobQueueStatus(defaultJobId, JobStatus.Success))
.Callback( new Action[]
{
() => statuses.Add(JobStatus.Success),
() => statuses.Add(JobStatus.Failed),
() => statuses.Add(JobStatus.Running)
});
var sut = new Sut(jobQueueRepositoryStub.Object);
sut.Do(defaultJobId);
Assert.True(statuses.Count == 3);
Assert.True(statuses.Any(x => x == JobStatus.Failed));
Assert.True(statuses.Any(x => x == JobStatus.Running));
Assert.True(statuses.Any(x => x == JobStatus.Success));
}
Callback extension method:
public static class Ext
{
public static void Callback<TRepo>(this ISetup<TRepo> repo, IEnumerable<Action> actions ) where TRepo : class {
foreach (var action in actions) {
action();
}
}
}
Sut (System Under Test) and other classes:
public enum JobStatus { Success, Failed, Running }
public interface IJobQueueRepository {
void UpdateJobQueueStatus(int id, JobStatus status);
}
public class Sut {
private readonly IJobQueueRepository _repository;
public Sut(IJobQueueRepository repository) {
_repository = repository;
}
public void Do(int jobId) {
_repository.UpdateJobQueueStatus(jobId, JobStatus.Success);
_repository.UpdateJobQueueStatus(jobId, JobStatus.Failed);
_repository.UpdateJobQueueStatus(jobId, JobStatus.Running);
}
}