I'm still learning ASP.NET MVC architecture and if any of my questions parts seem awful, sorry for the inconvenience that happened.
I want to add push notifications to my ASP.NET MVC web application which I have never used before.
I followed this article:
http://demo.dotnetawesome.com/push-notification-system-with-signalr
I'm using Entity Framework, and added the database connection string to my web.config file.
I used to create database connection via a class:
public class zSqlDb: DbContext
{
public zSqlDb(): base("Data Source=YEA-LAPTOP;Initial Catalog=db_ptweb;Integrated Security=True")
{
}
}
So in this article, he creates a class and there writes code to save data changes in the database.
This is the code:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Data.SqlClient;
using Microsoft.AspNet.SignalR;
namespace PushNotification
{
public class NotificationComponent
{
//Here we will add a function for register notification (will add sql dependency)
public void RegisterNotification(DateTime currentTime)
{
string conStr = ConfigurationManager.ConnectionStrings["sqlConString"].ConnectionString;
string sqlCommand = #"SELECT [ContactID],[ContactName],[ContactNo] from [dbo].[Contacts] where [AddedOn] > #AddedOn";
//you can notice here I have added table name like this [dbo].[Contacts] with [dbo], it's mandatory when you use Sql Dependency
using (SqlConnection con = new SqlConnection(conStr))
{
SqlCommand cmd = new SqlCommand(sqlCommand, con);
cmd.Parameters.AddWithValue("#AddedOn", currentTime);
if (con.State != System.Data.ConnectionState.Open)
{
con.Open();
}
cmd.Notification = null;
SqlDependency sqlDep = new SqlDependency(cmd);
sqlDep.OnChange += sqlDep_OnChange;
//we must have to execute the command here
using (SqlDataReader reader = cmd.ExecuteReader())
{
// nothing need to add here now
}
}
}
void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
{
//or you can also check => if (e.Info == SqlNotificationInfo.Insert) , if you want notification only for inserted record
if (e.Type == SqlNotificationType.Change)
{
SqlDependency sqlDep = sender as SqlDependency;
sqlDep.OnChange -= sqlDep_OnChange;
//from here we will send notification message to client
var notificationHub = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
notificationHub.Clients.All.notify("added");
//re-register notification
RegisterNotification(DateTime.Now);
}
}
public List<Contact> GetContacts(DateTime afterDate)
{
using (MyPushNotificationEntities dc = new MyPushNotificationEntities())
{
return dc.Contacts.Where(a => a.AddedOn > afterDate).OrderByDescending(a => a.AddedOn).ToList();
}
}
}
}
But I did to add records to the database by using the controller. So will this change the definition of the push notification process? If yes then I want to know how to match this code with mine.
Related
How do I change the timeout duration in logic apps web hook and also in chalkboard API.
The error message I get is.
"message": "Http request failed: the server did not respond within the timeout limit. Please see logic app limits at https://aka.ms/logic-apps-limits-and-config#http-limits"
You can refer to Perform long-running tasks with the webhook action pattern.
After understanding the webhook pattern, you need to design some code, you can refer to the following sample:
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;
using System.Threading;
using System.Net.Http;
using System;
namespace HttpToQueueWebhook
{
public static class HttpTrigger
{
[FunctionName("HttpTrigger")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "post")]HttpRequest req,
TraceWriter log,
[Queue("process")]out ProcessRequest process)
{
log.Info("Webhook request from Logic Apps received.");
string requestBody = new StreamReader(req.Body).ReadToEnd();
dynamic data = JsonConvert.DeserializeObject(requestBody);
string callbackUrl = data?.callbackUrl;
//This will drop a message in a queue that QueueTrigger will pick up
process = new ProcessRequest { callbackUrl = callbackUrl, data = "some data" };
return new AcceptedResult();
}
public static HttpClient client = new HttpClient();
/// <summary>
/// Queue trigger function to pick up item and do long work. Will then invoke
/// the callback URL to have logic app continue
/// </summary>
[FunctionName("QueueTrigger")]
public static void Run([QueueTrigger("process")]ProcessRequest item, TraceWriter log)
{
log.Info($"C# Queue trigger function processed: {item.data}");
//Thread.Sleep(TimeSpan.FromMinutes(3));
//ProcessResponse result = new ProcessResponse { data = "some result data" };
//handle your business here.
client.PostAsJsonAsync<ProcessResponse>(item.callbackUrl, result);
}
}
public class ProcessRequest
{
public string callbackUrl { get; set; }
public string data { get; set; }
}
public class ProcessResponse
{
public string data { get; set; }
}
}
The above code will first save your callbackUrl and the passed data to the queue, and then return the result of 202 to the logic app.
The QueueTrigger function will be triggered, and you can handle your business here.
You can call your http function like this in Azure logic app:
This solution can help you solve the http timeout problem. For more details, you can refer to this article.
I have a model for displaying a list of latest articles, and I would like to be able to define how many articles are displayed. I have created a property called DisplayNumberOfPressArticles and I would like to be able to access the value of this property from my controller.
Here is the model:
using Site.Helpers.Selections;
using Site.Models.Blocks.Data;
using EPiServer.DataAnnotations;
using EPiServer.Shell.ObjectEditing;
using System.ComponentModel.DataAnnotations;
namespace Site.Models.Blocks
{
[SiteContentType(GUID = "884202C2-61F1-4DF5-85A7-DC3D4E493F59")]
[SiteImageUrl]
public class LastArticlesTeaserBlock : SiteBlockData, PressOverviewData, ISpaceableData
{
[CultureSpecific]
public virtual string Heading { get; set; }
[Range(1, 1000)]
public virtual int DisplayNumberOfPressArticles { get; set; }
}
}
In my controller, I would like to take the value of DisplayNumberOfPressArticles as a limit for the .Take() query:
using System;
using System.Collections.Generic;
using Site.Models.Blocks;
using EPiServer.Web.Mvc;
using System.Web.Mvc;
using Site.Models.Pages;
using Site.Models.ViewModels;
using EPiServer.Find;
using EPiServer.Find.Api;
using EPiServer.Find.Cms;
using EPiServer.Find.Framework;
using EPiServer.Logging;
using ILogger = EPiServer.Logging.ILogger;
using EPiServer.Globalization;
namespace Site.Controllers
{
public class LastArticlesTeaserBlockController : BlockController<LastArticlesTeaserBlock>
{
private static readonly ILogger Logger = LogManager.GetLogger();
public override ActionResult Index(LastArticlesTeaserBlock currentContent)
{
var model = new LastArticlesTeaserViewModel
{
Headline = currentContent.Heading,
ArticlePages = GetArticlePages(),
PaddingTop = currentContent.PaddingTop,
PaddingBottom = currentContent.PaddingBottom
};
return PartialView(model);
}
private List<PressDetailsPage> GetArticlePages()
{
List<PressDetailsPage> result = new List<PressDetailsPage>();
IClient findClient = SearchClient.Instance;
var search = findClient.Search<PressDetailsPage>();
search = search
.Filter(sp => sp.IsDeleted.Match(false)).PublishedInCurrentLanguage()
.Filter(sp => sp.Headline.Exists() | sp.Description.Exists())
.Filter(sp => sp.Language.Name.Match(ContentLanguage.PreferredCulture.Name))
.OrderByDescending(sp => sp.PublishDate, SortMissing.Last)
.Take(??);
try
{
var searchResult = search.GetContentResult();
result.AddRange(searchResult);
}
catch (NullReferenceException e)
{
Logger.Error(e.ToString());
}
return result;
}
}
}
Sorry for the newbie question, but everything I have tried hasn't worked so far. I thought I could access the model by using .Take(LastArticlesTeaserBlock.DisplayNumberOfPressArticles);
How about changing your signature to something like GetArticlePages(int maxCount) and then invoking it like ArticlePages = GetArticlePages(currentContent.DisplayNumberOfPressArticles) in your Index method?
Your SearchClient class looks like a custom implementation and hard to tell if the bug is there.
Option 1:
Something like -- db.ArticleSet.OrderByDescending(t => t.Articles.Count).Take(10);
Option 2:
Or a more direct query.
Make life easier and break it down in two parts firs the query, they execution, then put it back together if you want.
Step 1
var articlesQuery = from x in Articles..
where x.IsDeleted == true ....
Step 2
var limitedArticlesQuery = articlesQuery.Take(25);
From client size send a int pageSize
var pagedProductQuery = articlesQuery.Skip(10 * pageSize).Take(10)
Company asked me to implement ASP.NET Zero web portal for our solutions. ASP.NET Zero based on ASP.NET Core + Angular Js. I am learning it since last 15 days. Now I wanted to know how to call stored procedures from ASP.NET Core and serve it in Angular.
Can Anyone explain with simple example?
You have several options to choose in order to call a SP from your Application Services regardless of SPA or MPA solution.
You can use Abp.Dapper nugget package
You can create a method in your EF DbContext which let you call any stored procedure.
Create a Repository class for your desired entity on Entity Framework part. It should inherit from RepositoryBase class and implement interface for related entity. Then add a method for calling a stored procedure.
For example:
public class UserProfileRepository : CommEngineRepositoryBase<UserProfile, int>, IUserProfileRepository
{
public UserProfileRepository(IDbContextProvider<CommEngineDbContext> dbContextProvider, IActiveTransactionProvider transactionProvider)
: base(dbContextProvider, transactionProvider)
{
}
public async Task<List<(string, int)>> GetCategoryAnalyticsForUser(int tenantId, DateTime startDate, DateTime endDate, long? userId)
{
EnsureConnectionOpen();
var nullableUserId = userId.HasValue ? (object)userId : DBNull.Value;
var output = new List<(string, int)>();
try
{
using (var command = CreateCommand("GetCategoryAnalyticsForUser",
CommandType.StoredProcedure,
new SqlParameter[]
{
new SqlParameter("#TenantId", tenantId),
new SqlParameter("#UserId", nullableUserId),
new SqlParameter("#StartDate", startDate),
new SqlParameter("#EndDate", endDate)
}
))
{
using (var dataReader = await command.ExecuteReaderAsync())
{
while (dataReader.Read())
{
string tag = dataReader["Tag"].ToString();
int.TryParse(dataReader["Count"].ToString(), out int count);
output.Add((tag, count));
}
}
}
return output;
}
catch (Exception ex)
{
throw new UserFriendlyException(ex.Message, ex.ToString());
}
finally
{
CloseDbConnection();
}
}
}
You call this from IUserProfileRepository interface.
Enjoy!
I want to log .net WEB API request-response to newly created file. So, I have implemented NLog mechanism in my project which works great. but still below code's .ToJSON() line doesn't get resolved. I can't figure out which namespace is required to use it. is there anything missing out?
I'm referring these two articles but still can't figure out.
1) http://www.codeproject.com/Articles/1028416/RESTful-Day-sharp-Request-logging-and-Exception-ha
2) http://www.strathweb.com/2012/06/using-nlog-to-provide-custom-tracing-for-your-asp-net-web-api/
.net namespaces
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http.Tracing;
using System.Net.Http;
using System.Text;
if (level != TraceLevel.Off)
{
if (traceAction != null && traceAction.Target != null)
{
category = category + Environment.NewLine + "Action Parameters : " + traceAction.Target.ToJSON(); //this ToJSON doesn't get resolved. which namespace should I include?
}
var record = new TraceRecord(request, category, level);
if (traceAction != null) traceAction(record);
Log(record);
}
There is no such method. The example from codeproject.com shows you how to make it yourself:
using System.Web.Script.Serialization;
using System.Data;
using System.Collections.Generic;
using System;
namespace WebApi.Helpers
{
public static class JSONHelper
{
/// <summary>
/// Extened method of object class, Converts an object to a json string.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string ToJSON(this object obj)
{
var serializer = new JavaScriptSerializer();
try
{
return serializer.Serialize(obj);
}
catch(Exception ex)
{
return "";
}
}
}
}
A better way is to use JSON.Net. It is most likely already referenced in your project and System.Web.Extensions.dll is ancient nowadays (its performance is terrible):
public void Trace(HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction)
{
if (level != TraceLevel.Off)
{
if (traceAction != null && traceAction.Target != null)
{
category = category + Environment.NewLine + "Action Parameters : " + JsonConvert.SerializeObject(traceAction.Target);
}
var record = new TraceRecord(request, category, level);
if (traceAction != null) traceAction(record);
Log(record);
}
}
I could really use some help understanding why this unit test is failing. I suspect it's due to the way I'm handling the streams. I have a number of other tests that successfully use this self-hosting server setup, but they all read services that return primitives like strings.
Here's the test in question:
using System.Net.Http;
using System.Threading;
using System.Web.Http.SelfHost;
using AttributeRouting.Web.Http.SelfHost;
using NUnit.Framework;
[TestFixture]
public class StreamControllerTests
{
[Test]
public void Can_get_simple_streaming_service_to_respond()
{
using (var config = new HttpSelfHostConfiguration("http://in-memory"))
{
config.Routes.MapHttpAttributeRoutes();
using (var server = new HttpSelfHostServer(config))
{
// I get the same behavior if I use HttpClient
using (var client = new HttpMessageInvoker(server))
{
using (var request = new HttpRequestMessage(HttpMethod.Get, "http://in-memory/stream/notepad"))
{
using (HttpResponseMessage response = client.SendAsync(request, CancellationToken.None).Result)
{
Assert.IsNotNull(response.Content);
// FAILS, content length is 0
Assert.Greater(response.Content.Headers.ContentLength, 0);
}
}
}
}
}
And here is the controller that feeds the test:
using System;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using AttributeRouting.Web.Mvc;
using MyUnitTests.Properties;
[GET("stream/notepad")]
public HttpResponseMessage StreamAnImageFromResources()
{
var imageStream = new MemoryStream(); // closed when stream content is read
Resources.a_jpeg_in_resources.Save(imageStream, ImageFormat.Jpeg);
try
{
HttpResponseMessage response = Request.CreateResponse();
// at this point, imageStream contains about 120K bytes
response.Content = new StreamContent(imageStream);
return response;
}
catch (Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.ServiceUnavailable, e);
}
}
I don't see anything really wrong but your test is more complicated than it needs to be.
Try this,
[Test]
public void Can_get_simple_streaming_service_to_respond2()
{
var config = new HttpConfiguration();
config.Routes.MapHttpAttributeRoutes();
var server = new HttpServer(config);
var client = new HttpClient(server);
var request = new HttpRequestMessage(HttpMethod.Get, "http://in-memory/stream/notepad");
HttpResponseMessage response = client.SendAsync(request, CancellationToken.None).Result;
Assert.IsNotNull(response.Content);
// FAILS, content length is 0
Assert.Greater(response.Content.Headers.ContentLength, 0);
}
EDIT: In the comments, Darrel gave me the true answer, which I'm moving to the answer body for visibility:
Check the position of your image stream after doing Save. You need to reset it back to 0 before passing to StreamContent. Also, you might want to consider doing GetManifestResourceStream instead, it will save copying the bytes into managed memory.