I am doing simple telegram echo bot on azure, which write telegramid of user to sql database.
I think i don't need to show code, but i can share with code to you if you require me to do this. I will explain by text.
I have function telegrambot which get response from telegram servers and send it to my UpdateService written by me where messages analyze and if message type is text i will write senders Id to my database.
Firstly i decide to just implement simple echo bot without database.
In startup file i write the next code
[assembly: FunctionsStartup(typeof(MyTelegramBot.Startup))]
namespace MyTelegramBot
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<UpdateService>();
builder.Services.AddLogging();
}
}
}
And i deploy it to Azure. Everything works fine, every message correctly come back to me.
Next i decide to Add database related files: entities, dbcontext
I have one table user and thats all.
Write operations was hold by IDbSaver
namespace MyTelegramBot.Interfaces
{
public interface IDbSaver<T> where T : class
{
Task<AlertMessage> RegisterUser(T entity);
}
}
Implementation of IDbSaver
namespace MyTelegramBot.Services
{
public class DbSaver<T> : IDbSaver<T> where T : class
{
protected DbSet<T> Dbset;
private readonly MyContext _context;
public DbSaver(MyContext context)
{
Dbset = context.Set<T>();
_context = context;
}
public async Task<AlertMessage> RegisterUser(T entity)
{
await Dbset.AddAsync(entity);
try
{
await _context.SaveChangesAsync();
return new AlertMessage()
{
Message = "Success."
};
}
catch(DbUpdateException ex) when(ex.InnerException is SqlException e)
{
if(e.Number == 2601)
{
return new AlertMessage()
{
Message = "Someone(maybe you?) registered same nickname."
};
}
return new AlertMessage()
{
Message = "some text"
};
}
}
}
}
Registered IDbSaver and Dbsaver in startup like
[assembly: FunctionsStartup(typeof(MyTelegramBot.Startup))]
namespace MyTelegramBot
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<UpdateService>();
builder.Services.AddLogging();
var connectionString = "connectionstring";
builder.Services.AddDbContext<MyContext>(s => s.UseSqlServer(connectionString));
builder.Services.AddScoped(typeof(IDbSaver<>), typeof(DbSaver<>));
}
}
}
And when i deploy it to Azure, deployment process goes well, no errors during publishing it to azure, but in Azure page of my function Alerting message is
MyTelegramBot: Could not load file or assembly 'Microsoft.Extensions.Logging, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. The system cannot find the file specified.
In the nuget package menu i found that microsoft.extensions.logging with version 7 and installed it, deploy again but error message still alive.
Guys, can you please help me.
I have next installed packages:
Microsoft.Azure.Functions.Extensions(1.1.0)
Microsoft.EntityFrameworkCore(7.0.0)
Microsoft.EntityFrameworkCOre.SqlServer(7.0.0)
Microsoft.Extensions.Logging(7.0.0)
Microsoft.Net.Sdk.Function(4.1.1)
Telegram.Bot(18.0.0)
Using:
.net 6.0
functions version v4
Related
I have an ASP.NET MVC application EducationalCenter with the following structure of projects:
DbContext file is EducationalCenterContext.cs in the Data project and looks as follows:
public sealed class EducationalCenterContext: DbContext
{
public DbSet<Student> Students { get; set; }
public EducationalCenterContext( DbContextOptions<EducationalCenterContext> options)
: base(options)
{
Database.EnsureCreated();
}
}
And in Startup.cs file, the dbContext configured as follows in ConfigureService():
services.AddDbContext<EducationalCenterContext>
(options => options.UseSqlServer("Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true"));
This is my working version to which I came by fixing errors when try to add-migration. However it seems awful to me that my web app has project reference to the Data project.
What was my first idea:
In appsettings.json I created this section :
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Then I created AppSettings class in the Common project:
public class AppSettings
{
public string ConnectionString { get; set; }
}
Then I try to pass ConnectionString in DAL via DI:
services.Configure<AppSettings>(Configuration.GetSection("ConnectionStrings"));
And created EducationalDbContext.cs:
public sealed class EducationalCenterContext: DbContext
{
private readonly string _connectionString;
public DbSet<Student> Students { get; set; }
public EducationalCenterContext( IOptions<AppSettings>, DbContextOptions<EducationalCenterContext> options)
: base(options)
{
_connectionString = app.Value.ConnectionString;
Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
}
But when I try to add-migration via PM Console, I ran into this error:
Could not load assembly 'EducationalCenter.Data'. Ensure it is referenced by the startup project 'EducationalCenter'
Then I added project reference and ran into the next error:
Unable to create an object of type 'EducationalCenterContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
Then I added services.AddDbContext<> in Startup.cs and came to the working version which I mentioned above.
So...
Is it normal that my web app has reference to the data access project?
Is it possible to configure EF in the Data project and ensure normal separation between DAL, BLL and web app?
Putting the context and configuration in a separate project is fine.
You got the first error because "Education Center" was set as start up project but did not have reference to data project.
The second error is because the migration builder needs some connection information in the data project to resolve the connection (to compare EF state and database state) to determine what changes are needed.
First add reference in your data project to:
Microsoft.EntityFrameworkCore.Design
Then add a context factory in your data project that migration console command will discover:
internal class MyContextFactory : IDesignTimeDbContextFactory<MyContext>
{
public MyContext CreateDbContext(string[] args)
{
var dbContextBuilder = new DbContextOptionsBuilder<MyContext>();
var connString = "myconnection string";
dbContextBuilder.UseSqlServer(connString);
return new MyContext(dbContextBuilder.Options);
}
}
I am very new to OWIN and trying to understand how OWIN mapping extension will work. I created an Empty ASP.Net project and referenced Owin, Microsoft.Owin, Microsoft.Owin.Host.SystemWeb packages.
I created a middleware class something like bello.
public class TempMiddleware : OwinMiddleware
{
public TempMiddleware(OwinMiddleware next)
: base(next)
{
}
public override Task Invoke(IOwinContext context)
{
return context.Response.WriteAsync("Response from Temp Middleware");
}
}
Here is my OWIN startup class.
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/temp", config => config.Use<TempMiddleware>());
}
}
I configured the portal project something like this.
When I run the project from VS2017, it returns HTTP Error 403.14 - Forbidden page.
Actually my expectation is, it should print "Response from Temp Middleware" message on the browser.
Any issues in my code ?
Thanks
Map() is used for branching the pipeline. In the delegate, the second parameter of the Map() method, you rather need to Run a middleware.
This is how your configuration code should be:
public void Configuration(IAppBuilder app)
{
app.Map("/temp", config => config.Run(async context =>
{
await context.Response.WriteAsync("Response from Temp Middleware");
}));
}
I have a simple trigger that is bound to a Service bus topic. I am trying to inject another service into the trigger but i am receiving an error:
Microsoft.Extensions.DependencyInjection.Abstractions: Unable to
resolve service for type 'AzureSearchSBTrigger.SimpleClass' while
attempting to activate 'AzureSearchSBTrigger.AzureServiceTrigger'.
If it remove the constructor the trigger works correctly and i can receive messages, etc.
This is an Azure function 2 (.net core) with Function Runtime Version: 2.0.12332.0
This is how it is setup (and not working)
The main function :
public AzureServiceTrigger(SimpleClass apiClient)
{
}
[FunctionName("AzureServiceTrigger")]
public async Task Run([ServiceBusTrigger("","",Connection = "SBConnectionString")]Message myQueueItem, ILogger log)
{
}
StartUp
[assembly: WebJobsStartup(typeof(StartUp))]
namespace AzureSearchSBTrigger
{
internal class StartUp : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
builder.Services.AddSingleton<SimpleClass>();
}
}
}
Simple Class
public class SimpleClass
{
public void Somethingsimple()
{
}
}
Fixed by updating the nuget package Microsoft.NET.Sdk.Functions from 1.0.24 -> 1.0.26
Use anything below Microsoft.NET.Sdk.Functions 3.0.1. I had 3.0.2 and I got this error, I had to downgrade but than again am using ASP.NetCore 2.2, so not sure if that has much to do with it
I have am working on a project that needs to support a read db and write db. I have decided to create two contexts accordingly. I have a Web API to interact with the db. I have an endpoint creates a user and another that fetches a user by id. The issue I'm running into is on the Development server, and Local instances, where an InMemory Db is used since development is rather rapid. The issue lies with the read context not giving me the data I stored with the write context. It thinks the table is empty. Upon further examination using the debugger, I am able to navigate and find the "missing" data. I'm not sure what is wrong.
Steps to reproduce
Here is an illustration of what I have in my project
public class WriteContext : IdentityDbContext<User>
{
public WriteContext(DbContextOptions<WriteContext> options) : base(options) {}
}
public class ReadContext : IdentityDbContext<User>
{
public ReadContext(DbContextOptions<ReadContext> options) : base(options) {}
}
public class UserController : Controller
{
private readonly WriteContext _write;
private readonly ReadContext _read;
// constructor injection here
// attributes...
public IActionResult Post(UserModel model)
{
var user = // map model to User
_write.Users.Add(user);
_write.SaveChanges();
return Ok(user);
}
// attributes...
public IActionResult Get(string userId)
{
var user = _read.Users.SingleOrDefault(x => x.Id == userId);
return Ok(user);
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// other stuff...
services.AddDbContext<WriteContext>(options => options.UseInMemoryDatabase("MemDb"));
services.AddDbContext<ReadContext>(options => options.UseInMemoryDatabase("MemDb"));
// other stuff
}
// other stuff
}
Add a user via write context and then try and fetch user via read context.
Further technical details
EF Core version: 2.0.1
Database Provider: InMemory
Operating system: macOS Sierra
IDE: Jetbrains Rider 2017.2
Corresponding GitHub Issue
I have been using MassTransit in my application and I have decided to see how Nimbus differs.
I am trying to write a proof of concept system, using Azure Service Bus and Nimbus with Autofac.
So far I have successfully written a Console Application which is configured to use Nimbus using Azure Service Bus and Autofac. I have followed all the examples that I can find online, in particular the PizzaSample from the Nimbus Samples.
This console application successfully starts up, configures the Bus, connects to Azure Service Bus and creates me a new Queue as expected in my Azure Service Bus. The application then begins to publish "Heartbeat" events, which seem to show that this application works fine.
Next I move onto a simple off the shelf, Visual Studio Templated MVC Application with no authentication.
I have again added Autofac, Nimbus, and Nimbus.Autofac and configured as per the above PizzaSample Web application. When I start the application, as expected Global.asax.cs is invoked, which configures Autofac and configures my Bus. When the Autofac container is built, my Bus is AutoActivated and the Instance of my Bus is Started. I can also see in Azure Service Bus that a queue for my web application has also been created successfully. However, this is where my application now hangs.
Upon further debugging, I seem to be able to hit my default controller and action (Home/Index) and I can step completely through all the code in this controller right upto and passed my "return View()". So all appears normal. However the view is never rendered and the browser sits at "Loading" until I kill "IIS Express".
If I amend my Web Applications Nimbus configuration to take out the Instance.Start(), and run the application without starting the bus, the application runs fine as expected, but obviously without the bus being started so I can't send/publish any messages.
Web Application Code
Global.asax.cs
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
ContainerConfig.Configure();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
protected void Application_End()
{
ContainerConfig.TearDown();
}
}
ContainerConfig.cs
public static class ContainerConfig
{
private static IContainer _container;
public static void Configure()
{
var builder = new ContainerBuilder();
builder.RegisterModule<NimbusModule>();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
_container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(_container));
}
public static void TearDown()
{
_container.Dispose();
}
}
NimbusModule.cs
public class NimbusModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
var connectionString = ConfigurationManager.ConnectionStrings["AzureServiceBus"].ConnectionString;
// You'll want a logger. There's a ConsoleLogger and a NullLogger if you really don't care. You can roll your
// own by implementing the ILogger interface if you want to hook it to an existing logging implementation.
builder.RegisterType<ConsoleLogger>()
.AsImplementedInterfaces()
.SingleInstance();
var messageContactAssembly = typeof(MyTestEvent).Assembly;
var handlerTypesProvider = new AssemblyScanningTypeProvider(messageContactAssembly);
builder.RegisterNimbus(handlerTypesProvider);
builder.Register(componentContext => new BusBuilder()
.Configure()
.WithConnectionString(connectionString)
.WithNames("Nimbus.Web", Environment.MachineName)
.WithTypesFrom(handlerTypesProvider)
.WithAutofacDefaults(componentContext)
.Build())
.As<IBus>()
.AutoActivate()
.OnActivated(c => c.Instance.Start())
.SingleInstance();
}
}
MyTestEvent.cs (From an independent referenced contract assembly)
public class MyTestEvent : IBusEvent
{
public MyTestEvent(Guid id)
{
Id= id;
}
public Guid Id { get; private set; }
}
HomeController.cs
public class HomeController : Controller
{
private readonly IBus _bus;
public HomeController(IBus bus)
{
_bus = bus;
}
public ActionResult Index()
{
_bus.Publish(new MyTestEvent(Guid.NewGuid()));
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
I obviously have some configuration wrong somewhere but I have spent hours looking at this and bashing my head against a wall. The closest that I can get to is thinking its something to do with the bus being started Async and perhaps somewhere the application is waiting for the Bus? But this is just a huge assumption and we all know assumptions are evil.
Has anyone seen this happen before and can offer any advice?