MVC Implementation of OAuthConsumer in DotNetOpenAuth specially for Google Address Book - dotnetopenauth

i have been searching on the net from last 2 days for MVC Implementation of OAuthConsumer Sample in DotNetOpenAuth, but still i did not found any solution.
i had also tried to convert OAuthConsumer implementation from WebForms to MVC, but still unable to implement it correctly.
can anybody please help by referring some place to find a converter sample.

After 2 days of struggle I resolved the issue as follows, but I think it needs some more improvement.
private string AccessToken
{
get { return (string)Session["GoogleAccessToken"]; }
set { Session["GoogleAccessToken"] = value; }
}
private InMemoryTokenManager TokenManager
{
get
{
var tokenManager = (InMemoryTokenManager)HttpContext.Application["GoogleTokenManager"];
if (tokenManager == null)
{
string consumerKey = ConfigurationManager.AppSettings["GoogleOAuthConsumerKey"];
string consumerSecret = ConfigurationManager.AppSettings["GoogleOAuthConsumerValue"];
if (!string.IsNullOrEmpty(consumerKey))
{
tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
HttpContext.Application["GoogleTokenManager"] = tokenManager;
}
}
return tokenManager;
}
}
public ActionResult GoogleSync()
{
var google = new WebConsumer(GoogleConsumer.ServiceDescription, this.TokenManager);
// Is Google calling back with authorization?
var accessTokenResponse = google.ProcessUserAuthorization();
if (accessTokenResponse != null)
{
this.AccessToken = accessTokenResponse.AccessToken;
XDocument contactsDocument = GoogleConsumer.GetContacts(google, this.AccessToken, 5, 1);
var contactList = new List<GMailContact>();
foreach (var entry in contactsDocument.Root.Elements(XName.Get("entry", "http://www.w3.org/2005/Atom")))
{
GMailContact newContact = new GMailContact { Name = string.Empty, Email = string.Empty };
var titleElement = entry.Element(XName.Get("title", "http://www.w3.org/2005/Atom"));
if (titleElement != null)
newContact.Name = titleElement.Value;
var emailElement = entry.Element(XName.Get("email", "http://schemas.google.com/g/2005"));
if (emailElement != null && emailElement.Attribute("address") != null)
{
newContact.Email = emailElement.Attribute("address").Value;
}
contactList.Add(newContact);
}
////var contacts = from entry in contactsDocument.Root.Elements(XName.Get("entry", "http://www.w3.org/2005/Atom"))
//// select new { Name = entry.Element(XName.Get("title", "http://www.w3.org/2005/Atom")).Value,
//// Email = (XName.Get("email", "http://schemas.google.com/g/2005") == null ? "" : entry.Element(XName.Get("email", "http://schemas.google.com/g/2005")).Attribute("address").Value) };
return View(contactList);
}
else if (this.AccessToken == null)
{
// If we don't yet have access, immediately request it.
GoogleConsumer.RequestAuthorization(google, GoogleConsumer.Applications.Contacts);
return this.Content("");
}
else
{
return this.Content("synchronization failed.");
}
}

There isn't any MVC sample of an OAuth Consumer that I'm aware of. But since an OAuth consumer really has nothing to do with the presentation framework it shouldn't be any different between web forms and MVC. You should be able to just lift the consumer-related code directly out of the web forms sample and have it work in MVC.
If that doesn't work, please add more to your question that explains the problems you're seeing.

Related

am working on updating a single attribute in the User Model which is the balance attribute,

how I can update a single value for an already existing row in the db by only having a parameters that I want to add it to this attribute
here is my code for a trivial way but didnt work
public bool BuyBook(int BookId, int UserId, int BookPrice){
using (var ctx = new OnlineBooksEntities())
{
User updatedCustomer = (from c in ctx.Users
where c.UserId == UserId
select c).FirstOrDefault();
updatedCustomer.Balance = BookPrice;
ctx.SaveChanges();
}
this.DeleteBook(BookId);
return true;
}
Add an sql query to the method solves the update aim
public bool BuyBook(int BookId, int UserId, int BookPrice)
{
try
{
using (var ctx = new OnlineBooksEntities())
{
User user = ctx.Users.Where(x => x.UserId == UserId).FirstOrDefault();
BookPrice = (int)user.Balance + BookPrice;
int noOfRowUpdated =
ctx.Database.ExecuteSqlCommand("Update Users set Balance = "+BookPrice+ " where UserId ="+UserId);
}
Updating basically means changing an existing row's value. Since you mentioned EF, you can do this by retrieving the object, changing its value, and saving it back. Thus you can do something like this:
using (var db = new MyContextDB())
{
var result = db.Books.SingleOrDefault(b => b.BookPrice == bookPrice);
if (result != null)
{
result.SomeValue = "Your new value here";
db.SaveChanges();
}
}

How to stop current job and start new job use quartz.net in asp.net mvc?

I've made a crawler on a website it has to read a website and fetch some values from it website.I've made use quartz.net and Asp.net MVC. but what is my problem? in fact,My problem is that for example,he/she the first time start for scraping a "Stackoverflow.com" about 5 hours and then he/she is decided stop "stackoverflow.com" and start a scrap new website.So,How can i do it?
[HttpPost]
public ActionResult Index(string keyword, string url)
{
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
scheduler.Start();
IJobDetail job = JobBuilder.Create<ScrapJob>()
.WithIdentity("MyScrapJob")
.UsingJobData("url", url)
.UsingJobData("keyword", keyword)
.Build();
ITrigger trigger = TriggerBuilder.Create().WithDailyTimeIntervalSchedule(
s => s.WithIntervalInSeconds(20).OnEveryDay().StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(0, 0))
).Build();
scheduler.ScheduleJob(job, trigger);
return View(db.Scraps.ToList());
}
public List<ScrapJob> Scraping(string url, string keyword)
{
int count = 0;
List<ScrapJob> scraps = new List<ScrapJob>();
ScrapJob scrap = null;
HtmlDocument doc = new HtmlDocument();
try
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
using (var response = (HttpWebResponse)request.GetResponse())
{
using (var stream = response.GetResponseStream())
{
doc.Load(stream, Encoding.GetEncoding("UTF-8"));
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//text()"))
{
if (node.InnerText.ToString().Contains(keyword))
{
count++;
scrap = new ScrapJob { Keyword = keyword, DateTime = System.DateTime.Now.ToString(), Count = count, Url = url };
}
}
}
}
}
catch (WebException ex)
{
Console.WriteLine(ex.Message);
}
// scraps.Add(scrap);
var isExist = db.Scraps.Where(s => s.Keyword == keyword && s.Count == scrap.Count).Max(s => (int?)s.Id) ?? 0;
if (isExist == 0)
{
db.Scraps.Add(scrap);
db.SaveChanges();
}
return scraps;
}
public void Execute(IJobExecutionContext context)
{
//ScrapJob scraps = null;
using (var scrap = new ScrapJob())
{
JobKey key = context.JobDetail.Key;
JobDataMap dataMap = context.JobDetail.JobDataMap;
string url = dataMap.GetString("url");
string keyword = dataMap.GetString("keyword");
scrap.Scraping(url, keyword);
}
}
I'm not sure why you picked QUARTZ, but here is something that I think will help you.
This is a code sample that interrupt and delete job by unique identifier
public void DeleteJob(JobKey jobKey)
{
var scheduler = StdSchedulerFactory.GetDefaultScheduler();
var executingJobs = scheduler.GetCurrentlyExecutingJobs();
if (executingJobs.Any(x => x.JobDetail.Key.Equals(jobKey)))
{
scheduler.Interrupt(jobKey);
}
scheduler.DeleteJob(jobKey);
}
But I believe you need to define what behavior you expect, because it can be a bit more complex for example:
If you like to just pause the job and resume it after finish with the other website /persist some state and progress/ or just log the progress
If you want them to run in parallel and process multiple sites simultaneously. (You just need to give different names instead of the hardcoded .WithIdentity("MyScrapJob") )
Also with scheduler.GetCurrentlyExecutingJobs() you can get the currently executing jobs, show them to the user and let him decide what to do.
Also looking at your action method I'm not sure whether this is the behavior you expect of that trigger. Also what bothers me is db.Scraps.ToList() you will materialize the whole table you can consider adding pagination as well in your case is not necessary because you will only show count but its mandatory if you have a lot of records in the grid.
About the scraping method
Instead of
var isExist = db.Scraps.Where(s => s.Keyword == keyword && s.Count == scrap.Count).Max(s => (int?)s.Id) ?? 0;
you can use .Any
var exists = db.Scraps.Any(s => s.Keyword == keyword && s.Count == scrap.Count);
this will return boolean and you can check if(!exists)
You can check https://github.com/AngleSharp/AngleSharp it's high performance web parsing library. Super easy to use as well.
I see possibility of duplicated records by keyword if you check them by keyword and count - not sure whether you want this or just want to update the existing record with it's counter
Good luck! I hope this answer helps you :)

Using Postal and Hangfire in Subsite

I have been trying to use Postal on my MVC5 site. When I host my webpage a subsite ie, http://localhost/Subsite I am receiving the error
The virtual path '/' maps to another application, which is not allowed
I have debugged it down to when the ControllerContext is being created the HttpContext isn't getting set correctly. Since I'm running Postal from Hangfire the HttpContext.Current is always null. Postal creates the ContollerContext using the code below.
ControllerContext CreateControllerContext()
{
// A dummy HttpContextBase that is enough to allow the view to be rendered.
var httpContext = new HttpContextWrapper(
new HttpContext(
new HttpRequest("", UrlRoot(), ""),
new HttpResponse(TextWriter.Null)
)
);
var routeData = new RouteData();
routeData.Values["controller"] = EmailViewDirectoryName;
var requestContext = new RequestContext(httpContext, routeData);
var stubController = new StubController();
var controllerContext = new ControllerContext(requestContext, stubController);
stubController.ControllerContext = controllerContext;
return controllerContext;
}
string UrlRoot()
{
var httpContext = HttpContext.Current;
if (httpContext == null)
{
return "http://localhost";
}
return httpContext.Request.Url.GetLeftPart(UriPartial.Authority) +
httpContext.Request.ApplicationPath;
}
How can I specify the UrlRoot so that instead of pulling the default of localhost to pull it based on my subsite?
I followed the directions here http://docs.hangfire.io/en/latest/tutorials/send-email.html to send my email. The method in the tutorial is below
public static void NotifyNewComment(int commentId)
{
// Prepare Postal classes to work outside of ASP.NET request
var viewsPath = Path.GetFullPath(HostingEnvironment.MapPath(#"~/Views/Emails"));
var engines = new ViewEngineCollection();
engines.Add(new FileSystemRazorViewEngine(viewsPath));
var emailService = new EmailService(engines);
// Get comment and send a notification.
using (var db = new MailerDbContext())
{
var comment = db.Comments.Find(commentId);
var email = new NewCommentEmail
{
To = "yourmail#example.com",
UserName = comment.UserName,
Comment = comment.Text
};
emailService.Send(email);
}
}
I found the issue was that the FileSystemRazorViewEngine was not being used bty postal. To get the this to work I had to make sure that the FileSystemRazorViewEngine was the first engine in the available. I then removed it because I did not want it to be the default engine. Below is my updated method.
public static void NotifyNewComment(int commentId)
{
// Prepare Postal classes to work outside of ASP.NET request
var viewsPath = Path.GetFullPath(HostingEnvironment.MapPath(#"~/Views/Emails"));
var eng = new FileSystemRazorViewEngine(viewsPath));
ViewEngines.Engines.Insert(0, eng);
var emailService = new EmailService(engines);
// Get comment and send a notification.
using (var db = new MailerDbContext())
{
var comment = db.Comments.Find(commentId);
var email = new NewCommentEmail
{
To = "yourmail#example.com",
UserName = comment.UserName,
Comment = comment.Text
};
emailService.Send(email);
ViewEngines.Engines.RemoveAt(0)
}
}
Below is another possible solution that I think is more elegant than above. It also resolves an issue that appears when accessing the MVC application while the background process is being executed.
public static void SendTypedEmailBackground()
{
try
{
var engines = new ViewEngineCollection();
var viewsPath = Path.GetFullPath(HostingEnvironment.MapPath(#"~/Views/Emails"));
var eng = new FileSystemRazorViewEngine(viewsPath);
engines.Add(eng);
var email = new WebApplication1.Controllers.EmailController.TypedEmail();
email.Date = DateTime.UtcNow.ToString();
IEmailService service = new Postal.EmailService(engines);
service.Send(email);
}
catch(Exception ex)
{
throw ex;
}
}

Missing Access Token on IsAuthorized at Attribute

I
have been following the DotnetOPenAuth example of the oAuth authorization.
on the OAuth2AuthorizeAttribute i am always getting "Missing Access Token."
I have checked again and again i am passing the access token via the header and its been set nicely within the request object.
What could be the reason for that?
Here is the code
protected virtual bool IsAuthorized(HttpActionContext actionContext, out IPrincipal user)
{
var signingKey = ApplicationSettings.SigningKey(ApplicationSettings.KeyType.Public);
var resourceKey = ApplicationSettings.ResoureKey(ApplicationSettings.KeyType.Private);
using (var signing = signingKey)
using (var resource = resourceKey)
{
base.OnAuthorization(actionContext);
// TODO FIXME dnoa doesn't support HttpRequestMessage - manually creating HttpRequestMessageProperty until they do
var request = new HttpRequestMessageProperty();
if (actionContext.Request.Headers.Authorization != null)
{
request.Headers[HttpRequestHeader.Authorization] =
actionContext.Request.Headers.Authorization.ToString();
}
else
{
request.Headers[HttpRequestHeader.Authorization] = null;
}
var requestUri = actionContext.Request.RequestUri;
var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(signing, resource));
try
{
user = resourceServer.GetPrincipal(request, requestUri, _oauth2Scopes);
return true;
}
catch (ProtocolFaultResponseException x)
{
user = null;
return false;
}
}
}
I found the problem.
In the Authorization header need to have the text Bearer before the access token for example
Bearer gAAAALfeAiFpUFOY8bJggyQ

Unit testing a controller that depends on a session variable

I have a controller that depends on a Session variable. In order to unit test this controller, I came up with the following solution. It works but I'm wondering if there is a better/cleaner way. Thanks
Controller
public JsonResult UpdateStatus(ImageUpdateStatus imageUpdateStatus, SessionStateItemCollection sessionItems = null)
{
var data = new object();
string status = null;
ImageInfo imageInfo = new ImageInfo();
IImageInfoServices svcImageInfo = new ImageInfoServicesRepository();
imageInfo = svcImageInfo.GetImageByImageId(imageUpdateStatus.ImageId);
IDeviceControlServices svcDevice = new DeviceControlServicesRespository();
IPVSCommandServices svcPVSCmds = new PVSCommandServicesRespository();
if (imageUpdateStatus.Task == "prep")
{
List<UpdateReasonForm> updateReasonForms;
if (sessionItems != null)
{
updateReasonForms = sessionItems["UpdateReasonForms"] as List<UpdateReasonForm>;
}
else
{
updateReasonForms = Session["UpdateReasonForms"] as List<UpdateReasonForm>;
}
foreach (var item in updateReasonForms)
{
if (item.ImageId == imageInfo.ImageId)
{
status = svcPVSCmds.PrepImage(imageInfo, item.NewVersion);
}
}
data = new
{
status
};
}
if (imageUpdateStatus.Task == "boot")
{
status = svcDevice.Boot(imageInfo.ImageId);
data = new
{
status
};
}
return this.Json(data, JsonRequestBehavior.AllowGet);
}
Unit Test
[TestMethod()]
public void UpdateStatusTest()
{
BuildController target = new BuildController(); // TODO: Initialize to an appropriate value
ImageUpdateStatus imageUpdateStatus = new ImageUpdateStatus(); // TODO: Initialize to an appropriate value
imageUpdateStatus.ImageId = 3;
imageUpdateStatus.Task = "prep";
UpdateReasonForm updateReasonForm = new UpdateReasonForm();
updateReasonForm.ImageId = 3;
updateReasonForm.NewVersion = "TestThis";
List<UpdateReasonForm> updateReasonForms = new List<UpdateReasonForm>();
updateReasonForms.Add(updateReasonForm);
var sessionItems = new SessionStateItemCollection();
sessionItems["UpdateReasonForms"] = updateReasonForms;
JsonResult actual;
actual = target.UpdateStatus(imageUpdateStatus, sessionItems);
}
Instead of passing in the session values as a parameter you can mock the session state like here:
How do you mock the session object collection using Moq
You have a dependency on Session. You could move your code into a testable method where you inject the dependency at the method level. It looks like you are on this path I would just abstract the code into its own method allowing you to test the functionality regardless of the whether the data comes from session or not.
public JsonResult UpdateStatusDependencyInjection(ImageUpdateStatus imageUpdateStatus, Dictionary<string, object> sessionValues)
{
var data = new object();
string status = null;
ImageInfo imageInfo = new ImageInfo();
IImageInfoServices svcImageInfo = new ImageInfoServicesRepository();
imageInfo = svcImageInfo.GetImageByImageId(imageUpdateStatus.ImageId);
IDeviceControlServices svcDevice = new DeviceControlServicesRespository();
IPVSCommandServices svcPVSCmds = new PVSCommandServicesRespository();
if (imageUpdateStatus.Task == "prep")
{
List<UpdateReasonForm> updateReasonForms;
if (sessionItems != null)
{
updateReasonForms = sessionItems["UpdateReasonForms"] as List<UpdateReasonForm>;
}
else
{
updateReasonForms = Session["UpdateReasonForms"] as List<UpdateReasonForm>;
}
foreach (var item in updateReasonForms)
{
if (item.ImageId == imageInfo.ImageId)
{
status = svcPVSCmds.PrepImage(imageInfo, item.NewVersion);
}
}
data = new
{
status
};
}
if (imageUpdateStatus.Task == "boot")
{
status = svcDevice.Boot(imageInfo.ImageId);
data = new
{
status
};
}
return this.Json(data, JsonRequestBehavior.AllowGet);
}
http://codingsmith.co.za/a-better-way-of-working-with-httpcontext-session-in-mvc/
This is my implementation of an interface wrapper for Session.
Its currently in production and works fine, its injected into my controllers, but I can use one of the other implementations manually when testing

Resources